TCG TPM2 r1p59 Part4 SuppRoutines Code Pub
TCG TPM2 r1p59 Part4 SuppRoutines Code Pub
Family “2.0”
Level 00 Revision 01.59
November 8, 2019
Published
Contact: [email protected]
TCG Published
Copyright © TCG 2006-2020
TCG
Trusted Platform Module Library Part 4: Supporting Routines
Copyright Licenses:
• Trusted Computing Group (TCG) grants to the user of the source code in this specification (the
“Source Code”) a worldwide, irrevocable, nonexclusive, royalty free, copyright license to reproduce,
create derivative works, distribute, display and perform the Source Code and derivative works
thereof, and to grant others the rights granted herein.
• The TCG grants to the user of the other parts of the specification (other than the Source Code) the
rights to reproduce, distribute, display, and perform the specification solely for the purpose of
developing products based on such documents.
Source Code Distribution Conditions:
• Redistributions of Source Code must retain the above copyright licenses, this list of conditions and
the following disclaimers.
• Redistributions in binary form must reproduce the above copyright licenses, this list of conditions and
the following disclaimers in the documentation and/or other materials provided with the distribution.
Disclaimers:
• THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF
LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH
RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) THAT
MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. Contact TCG
Administration ([email protected]) for information on specification licensing rights
available through TCG membership agreements.
• THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED WARRANTIES
WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR NONINFRINGEMENT OF
INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY OTHERWISE ARISING OUT OF ANY
PROPOSAL, SPECIFICATION OR SAMPLE.
• Without limitation, TCG and its members and licensors disclaim all liability, including liability for
infringement of any proprietary rights, relating to use of information in this specification and to the
implementation of this specification, and TCG disclaims all liability for cost of procurement of
substitute goods or services, lost profits, loss of use, loss of data or any incidental, consequential,
direct, indirect, or special damages, whether under contract, tort, warranty or otherwise, arising in any
way out of use or reliance upon this specification or any information herein.
Any marks and brands contained herein are the property of their respective owners.
CONTENTS
1 Scope ................................................................................................................................... 1
2 Terms and definitions ........................................................................................................... 1
3 Symbols and abbreviated terms ............................................................................................ 1
4 Automation ........................................................................................................................... 1
4.1 Configuration Parser ................................................................................................... 1
4.2 Structure Parser .......................................................................................................... 2
4.2.1 Introduction .......................................................................................................... 2
4.2.2 Unmarshaling Code Prototype .............................................................................. 2
8 Subsystem........................................................................................................................ 284
8.1 CommandAudit.c ..................................................................................................... 284
8.1.1 Introduction ...................................................................................................... 284
8.1.2 Includes ........................................................................................................... 284
8.1.3 Functions ......................................................................................................... 284
1 Scope
This part contains C code that describes the algorithms and methods used by the command code in TPM
2.0 Part 3. The code in this document augments TPM 2.0 Part 2 and TPM 2.0 Part 3 to provide a
complete description of a TPM, including the supporting framework for the code that performs the
command actions.
Any TPM 2.0 Part 4 code may be replaced by code that provides similar results when interfacing to the
action code in TPM 2.0 Part 3. The behavior of code in this document that is not included in an annex is
normative, as observed at the interfaces with TPM 2.0 Part 3 code. Code in an annex is provided for
completeness, that is, to allow a full implementation of the specification from the provided code.
The code in parts 3 and 4 is written to define the behavior of a compliant TPM. In some cases (e.g.,
firmware update), it is not possible to provide a compliant implementation. In those cases, any
implementation provided by the vendor that meets the general description of the function provided in TPM
2.0 Part 3 would be compliant.
The code in parts 3 and 4 is not written to meet any particular level of conformance nor does this
specification require that a TPM meet any particular level of conformance.
For the purposes of this document, the terms and definitions given in TPM 2.0 Part 1 apply.
For the purposes of this document, the symbols and abbreviated terms given in TPM 2.0 Part 1 apply.
4 Automation
TPM 2.0 Part 2 and 3 are constructed so that they can be processed by an automated parser. For
example, TPM 2.0 Part 2 can be processed to generate header file contents such as structures, typedefs,
and enums. TPM 2.0 Part 3 can be processed to generate command and response marshaling and
unmarshaling code.
The automated processor is not provided by the TCG. It was used to generate the Microsoft Visual Studio
TPM simulator files. These files are not specification reference code, but rather design examples.
The automation produces TPM_Types.h, a header representing TPM 2.0 Part 2. It also produces, for
each major clause of Part 4, a header of the form _fp.h with the function prototypes.
EXAMPLE The header file for SessionProcess.c is SessionProcess_fp.h.
The TPM configuration is largely defined by TpmProfiles.h. This file may be edited in order to change the
algorithms and commands supported by a TPM implementation.
A parser exists to process a Word document that defines the TPM configuration. This parser is used to
create TpmProfiles.h.
4.2.1 Introduction
The program that processes the tables in TPM 2.0 Part 2 is called "The TPM 2.0 Part 2 Structure Parser."
NOTE A Perl script was used to parse the tables in TPM 2.0 Part 2 to produce the header files and unmarshaling code
in for the reference implementation.
The TPM 2.0 Part 2 Structure Parser takes as input the files produced by the TPM 2.0 Part 2
Configuration Parser and the same TPM 2.0 Part 2 specification that was used as input to the TPM 2.0
Part 2 Configuration Parser. The TPM 2.0 Part 2 Structure Parser will generate all of the C structure
constant definitions that are required by the TPM interface. Additionally, the parser will generate
unmarshaling code for all structures passed to the TPM, and marshaling code for structures passed from
the TPM.
The unmarshaling code produced by the parser uses the prototypes defined below. The unmarshaling
code will perform validations of the data to ensure that it is compliant with the limitations on the data
imposed by the structure definition and use the response code provided in the table if not.
EXAMPLE: The definition for a TPMI_RH_PROVISION indicates that the primitive data type is a TPM_HANDLE and the
only allowed values are TPM_RH_OWNER and TPM_RH_PLATFORM. The definition also indicates that the
TPM shall indicate TPM_RC_HANDLE if the input value is not none of these values. The unmarshaling code
will validate that the input value has one of those allowed values and return TPM_RC_HANDLE if not.
The sections below describe the function prototypes for the marshaling and unmarshaling code that is
automatically generated by the TPM 2.0 Part 2 Structure Parser. These prototypes are described here as
the unmarshaling and marshaling of various types occurs in places other than when the command is
being parsed or the response is being built. The prototypes and the description of the interface are
intended to aid in the comprehension of the code that uses these auto-generated routines.
The general form for the unmarshaling code for a simple type or a structure is:
Where:
TYPE name of the data type or structure
*target location in the TPM memory into which the data from **buffer is placed
**buffer location in input buffer containing the most significant octet (MSO) of
*target
*size number of octets remaining in **buffer
When the data is successfully unmarshaled, the called routine will return TPM_RC_SUCCESS.
Otherwise, it will return a Format-One response code (see TPM 2.0 Part 2).
If the data is successfully unmarshaled, *buffer is advanced point to the first octet of the next parameter
in the input buffer and size is reduced by the number of octets removed from the buffer.
When the data type is a simple type, the parser will generate code that will unmarshal the underlying type
and then perform checks on the type as indicated by the type definition.
When the data type is a structure, the parser will generate code that unmarshals each of the structure
elements in turn and performs any additional parameter checks as indicated by the data type.
Page 2 TCG Published Family “2.0”
November 8, 2019 Copyright © TCG 2006-2020 Level 00 Revision 01.59
Part 4: Supporting Routines Trusted Platform Module Library
When a union is defined, an extra parameter is defined for the unmarshaling code. This parameter is the
selector for the type. The unmarshaling code for the union will unmarshal the type indicated by the
selector.
The function prototype for a union has the form:
where:
TYPE name of the union type or structure
*target location in the TPM memory into which the data from **buffer is placed
**buffer location in input buffer containing the most significant octet (MSO) of
*target
*size number of octets remaining in **buffer
selector union selector that determines what will be unmarshaled into *target
In some cases, the structure definition allows an optional “null” value. The “null” value allows the use of
the same C type for the entity even though it does not always have the same members.
For example, the TPMI_ALG_HASH data type is used in many places. In some cases, TPM_ALG_NULL
is permitted and in some cases it is not. If two different data types had to be defined, the interfaces and
code would become more complex because of the number of cast operations that would be necessary.
Rather than encumber the code, the “null” value is defined and the unmarshaling code is given a flag to
indicate if this instance of the type accepts the “null” parameter or not. When the data type has a “null”
value, the function prototype is
The parser detects when the type allows a “null” value and will always include flag in any call to
unmarshal that type. flag TRUE indicates that null is accepted.
4.2.2.4 Arrays
Any data type may be included in an array. The function prototype use to unmarshal an array for a TYPE is
The generated code for an array uses a count-limited loop within which it calls the unmarshaling code for
TYPE.
The general form for the marshaling code for a simple type or a structure is:
Where:
An extra parameter is defined for the marshaling function of a union. This parameter is the selector for the
type. The marshaling code for the union will marshal the type indicated by the selector.
The function prototype for a union has the form:
The parameters have a similar meaning as those in 4.2.2.2 but the data movement is from source to
buffer.
4.2.3.3 Arrays
Any type may be included in an array. The function prototype use to unmarshal an array is:
4.2.3.4 The generated code for an array uses a count- limited loop within which it calls
the marshaling code for TYPE .Table-driven Marshaling
The most recent versions of the TPM code includes the option to use table-driven marshaling rather that
the procedural marshaling described in previous clauses in 4.2.2. The structure and processing of this
code is complex and is provided in the code.
The Command / Response tables in Part 3 of this specification are processed by scripts to produce the
command-specific data structures used by functions in this TPM 2.0 Part 4. They are:
• CommandAttributeData.h -- This file contains the command attributes reported by
TPM2_GetCapability.
• CommandAttributes.h – This file contains the definition of command attributes that are extracted by
the parsing code. The file mainly exists to ensure that the parsing code and the function code are
using the same attributes.
• CommandDispatchData.h – This file contains the data definitions for the table driven version of the
command dispatcher.
Part 3 parsing also produces special function prototype files as described in 4.4.
For functions that have entry definitions not defined by Part 3 tables. a script is used to extracts function
prototypes from the code. For each .c file that is not in Part 3, a file with the same name is created with a
suffix of _fp.h. For example, the function prototypes for Create.c will be placed in a file called Create_fp.h.
The _fp.h is added because some files have two types of associated headers: the one containing the
function prototypes for the file and another containing definitions that are specific to that file.
In some cases, a function will be replaced by a macro. The macro is defined in the .c file and extracted by
the function prototype processor. A special comment tag (“//%”) is used to indicate that the line is to be
included in the function prototype file. If the “//%” tag occurs at the start of the line, it is deleted. If it occurs
later in the line, it is preserved. Removing the “//%/ at the start of the line allows the macro to be placed in
the .c file with the tag as a prefix, and then show up in the _fp.h file as the actual macro. This allows the
code that includes that function prototype code to use the appropriate macro.
For files that that contain the command actions, a special _fp.h file is created from the tables in Part 3.
These files contain:
• the definition of the input and output structure of the function;
• definition of command-specific return code modifiers (parameter identifiers); and
• the function prototype for the command action function.
Create_fp.h (shown below) is prototypical of the command _fp.h files.
4 typedef struct {
5 TPMI_DH_OBJECT parentHandle;
6 TPM2B_SENSITIVE_CREATE inSensitive;
7 TPM2B_PUBLIC inPublic;
8 TPM2B_DATA outsideInfo;
9 TPML_PCR_SELECTION creationPCR;
10 } Create_In;
11 typedef struct {
12 TPM2B_PRIVATE outPrivate;
13 TPM2B_PUBLIC outPublic;
14 TPM2B_CREATION_DATA creationData;
15 TPM2B_DIGEST creationHash;
16 TPMT_TK_CREATION creationTicket;
17 } Create_Out;
Function prototype
23 TPM_RC
24 TPM2_Create(
25 Create_In *in,
26 Create_Out *out
27 );
28 #endif // _Create_FP_H_
29 #endif // CC_Create
4.5 Portability
Where reasonable, the code is written to be portable. There are a few known cases where the code is not
portable. Specifically, the handling of bit fields will not always be portable. The bit fields are marshaled
and unmarshaled as a simple element of the underlying type. For example, a TPMA_SESSION is defined
as a bit field in an octet (BYTE). When sent on the interface a TPMA_SESSION will occupy one octet.
When unmarshaled, it is unmarshaled as a UINT8. The ramifications of this are that a TPMA_SESSION
will occupy the 0th octet of the structure in which it is placed regardless of the size of the structure.
Many compilers will pad a bit field to some "natural" size for the processor, often 4 octets, meaning that
sizeof(TPMA_SESSION) would return 4 rather than 1 (the canonical size of a TPMA_SESSION).
For a little endian machine, padding of bit fields should have little consequence since the 0 th octet always
contains the 0th bit of the structure no matter how large the structure. However, for a big endian machine,
the 0th bit will be in the highest numbered octet. When unmarshaling a TPMA_SESSION, the current
unmarshaling code will place the input octet at the 0 th octet of the TPMA_SESSION. Since the 0th octet is
most significant octet, this has the effect of shifting all the session attribute bits left by 24 places.
As a consequence, someone implementing on a big endian machine should do one of two things:
allocate all structures as packed to a byte boundary (this may not be possible if the processor does
not handle unaligned accesses); or
modify the code that manipulates bit fields that are not defined as being the alignment size of the
system.
For many RISC processors, option #2 would be the only choice. This is may not be a terribly daunting
task since only two attribute structures are not 32-bits (TPMA_SESSION and TPMA_LOCALITY).
5 Header Files
5.1 Introduction
The files in this section are used to define values that are used in multiple parts of the specification and
are not confined to a single module.
5.2 BaseTypes.h
1 #ifndef _BASE_TYPES_H_
2 #define _BASE_TYPES_H_
NULL definition
3 #ifndef NULL
4 #define NULL (0)
5 #endif
6 typedef uint8_t UINT8;
7 typedef uint8_t BYTE;
8 typedef int8_t INT8;
9 typedef int BOOL;
10 typedef uint16_t UINT16;
11 typedef int16_t INT16;
12 typedef uint32_t UINT32;
13 typedef int32_t INT32;
14 typedef uint64_t UINT64;
15 typedef int64_t INT64;
16 #endif // _BASE_TYPES_H_
5.3 Capabilities.h
This file contains defines for the number of capability values that will fit into the largest data buffer.
These defines are used in various function in the "support" and the "subsystem" code groups. A module
that supports a type that is returned by a capability will have a function that returns the capabilities of the
type.
1 #ifndef _CAPABILITIES_H
2 #define _CAPABILITIES_H
3 #define MAX_CAP_DATA (MAX_CAP_BUFFER - sizeof(TPM_CAP)-sizeof(UINT32))
4 #define MAX_CAP_ALGS (MAX_CAP_DATA / sizeof(TPMS_ALG_PROPERTY))
5 #define MAX_CAP_HANDLES (MAX_CAP_DATA / sizeof(TPM_HANDLE))
6 #define MAX_CAP_CC (MAX_CAP_DATA / sizeof(TPM_CC))
7 #define MAX_TPM_PROPERTIES (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PROPERTY))
8 #define MAX_PCR_PROPERTIES (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PCR_SELECT))
9 #define MAX_ECC_CURVES (MAX_CAP_DATA / sizeof(TPM_ECC_CURVE))
10 #define MAX_TAGGED_POLICIES (MAX_CAP_DATA / sizeof(TPMS_TAGGED_POLICY))
11 #define MAX_ACT_DATA (MAX_CAP_DATA / sizeof(TPMS_ACT_DATA))
12 #define MAX_AC_CAPABILITIES (MAX_CAP_DATA / sizeof(TPMS_AC_OUTPUT))
13 #endif
5.4 CommandAttributeData.h
1 #ifdef _COMMAND_CODE_ATTRIBUTES_
2 #include "CommandAttributes.h"
3 #if COMPRESSED_LISTS
4 # define PAD_LIST 0
5 #else
6 # define PAD_LIST 1
7 #endif
This is the command code attribute array for GetCapability(). Both this array and s_commandAttributes
provides command code attributes, but tuned for different purpose
383 (IS_IMPLEMENTED+HANDLE_1_ADMIN+HANDLE_2_USER+PP_COMMAND)),
384 #endif
385 #if (PAD_LIST || CC_EvictControl)
386 (COMMAND_ATTRIBUTES)(CC_EvictControl * // 0x0120
387 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
388 #endif
389 #if (PAD_LIST || CC_HierarchyControl)
390 (COMMAND_ATTRIBUTES)(CC_HierarchyControl * // 0x0121
391 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
392 #endif
393 #if (PAD_LIST || CC_NV_UndefineSpace)
394 (COMMAND_ATTRIBUTES)(CC_NV_UndefineSpace * // 0x0122
395 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
396 #endif
397 #if (PAD_LIST )
398 (COMMAND_ATTRIBUTES)(0), // 0x0123
399 #endif
400 #if (PAD_LIST || CC_ChangeEPS)
401 (COMMAND_ATTRIBUTES)(CC_ChangeEPS * // 0x0124
402 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
403 #endif
404 #if (PAD_LIST || CC_ChangePPS)
405 (COMMAND_ATTRIBUTES)(CC_ChangePPS * // 0x0125
406 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
407 #endif
408 #if (PAD_LIST || CC_Clear)
409 (COMMAND_ATTRIBUTES)(CC_Clear * // 0x0126
410 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
411 #endif
412 #if (PAD_LIST || CC_ClearControl)
413 (COMMAND_ATTRIBUTES)(CC_ClearControl * // 0x0127
414 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
415 #endif
416 #if (PAD_LIST || CC_ClockSet)
417 (COMMAND_ATTRIBUTES)(CC_ClockSet * // 0x0128
418 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
419 #endif
420 #if (PAD_LIST || CC_HierarchyChangeAuth)
421 (COMMAND_ATTRIBUTES)(CC_HierarchyChangeAuth * // 0x0129
422 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)),
423 #endif
424 #if (PAD_LIST || CC_NV_DefineSpace)
425 (COMMAND_ATTRIBUTES)(CC_NV_DefineSpace * // 0x012A
426 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)),
427 #endif
428 #if (PAD_LIST || CC_PCR_Allocate)
429 (COMMAND_ATTRIBUTES)(CC_PCR_Allocate * // 0x012B
430 (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)),
431 #endif
432 #if (PAD_LIST || CC_PCR_SetAuthPolicy)
433 (COMMAND_ATTRIBUTES)(CC_PCR_SetAuthPolicy * // 0x012C
434 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)),
435 #endif
436 #if (PAD_LIST || CC_PP_Commands)
437 (COMMAND_ATTRIBUTES)(CC_PP_Commands * // 0x012D
438 (IS_IMPLEMENTED+HANDLE_1_USER+PP_REQUIRED)),
439 #endif
440 #if (PAD_LIST || CC_SetPrimaryPolicy)
441 (COMMAND_ATTRIBUTES)(CC_SetPrimaryPolicy * // 0x012E
442 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)),
443 #endif
444 #if (PAD_LIST || CC_FieldUpgradeStart)
445 (COMMAND_ATTRIBUTES)(CC_FieldUpgradeStart * // 0x012F
446 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+PP_COMMAND)),
447 #endif
448 #if (PAD_LIST || CC_ClockRateAdjust)
515 #endif
516 #if (PAD_LIST || CC_FieldUpgradeData)
517 (COMMAND_ATTRIBUTES)(CC_FieldUpgradeData * // 0x0141
518 (IS_IMPLEMENTED+DECRYPT_2)),
519 #endif
520 #if (PAD_LIST || CC_IncrementalSelfTest)
521 (COMMAND_ATTRIBUTES)(CC_IncrementalSelfTest * // 0x0142
522 (IS_IMPLEMENTED)),
523 #endif
524 #if (PAD_LIST || CC_SelfTest)
525 (COMMAND_ATTRIBUTES)(CC_SelfTest * // 0x0143
526 (IS_IMPLEMENTED)),
527 #endif
528 #if (PAD_LIST || CC_Startup)
529 (COMMAND_ATTRIBUTES)(CC_Startup * // 0x0144
530 (IS_IMPLEMENTED+NO_SESSIONS)),
531 #endif
532 #if (PAD_LIST || CC_Shutdown)
533 (COMMAND_ATTRIBUTES)(CC_Shutdown * // 0x0145
534 (IS_IMPLEMENTED)),
535 #endif
536 #if (PAD_LIST || CC_StirRandom)
537 (COMMAND_ATTRIBUTES)(CC_StirRandom * // 0x0146
538 (IS_IMPLEMENTED+DECRYPT_2)),
539 #endif
540 #if (PAD_LIST || CC_ActivateCredential)
541 (COMMAND_ATTRIBUTES)(CC_ActivateCredential * // 0x0147
542 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+HANDLE_2_USER+ENCRYPT_2)),
543 #endif
544 #if (PAD_LIST || CC_Certify)
545 (COMMAND_ATTRIBUTES)(CC_Certify * // 0x0148
546 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+HANDLE_2_USER+ENCRYPT_2)),
547 #endif
548 #if (PAD_LIST || CC_PolicyNV)
549 (COMMAND_ATTRIBUTES)(CC_PolicyNV * // 0x0149
550 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ALLOW_TRIAL)),
551 #endif
552 #if (PAD_LIST || CC_CertifyCreation)
553 (COMMAND_ATTRIBUTES)(CC_CertifyCreation * // 0x014A
554 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)),
555 #endif
556 #if (PAD_LIST || CC_Duplicate)
557 (COMMAND_ATTRIBUTES)(CC_Duplicate * // 0x014B
558 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_DUP+ENCRYPT_2)),
559 #endif
560 #if (PAD_LIST || CC_GetTime)
561 (COMMAND_ATTRIBUTES)(CC_GetTime * // 0x014C
562 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)),
563 #endif
564 #if (PAD_LIST || CC_GetSessionAuditDigest)
565 (COMMAND_ATTRIBUTES)(CC_GetSessionAuditDigest * // 0x014D
566 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)),
567 #endif
568 #if (PAD_LIST || CC_NV_Read)
569 (COMMAND_ATTRIBUTES)(CC_NV_Read * // 0x014E
570 (IS_IMPLEMENTED+HANDLE_1_USER+ENCRYPT_2)),
571 #endif
572 #if (PAD_LIST || CC_NV_ReadLock)
573 (COMMAND_ATTRIBUTES)(CC_NV_ReadLock * // 0x014F
574 (IS_IMPLEMENTED+HANDLE_1_USER)),
575 #endif
576 #if (PAD_LIST || CC_ObjectChangeAuth)
577 (COMMAND_ATTRIBUTES)(CC_ObjectChangeAuth * // 0x0150
578 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+ENCRYPT_2)),
579 #endif
580 #if (PAD_LIST || CC_PolicySecret)
779 #endif
780 #if (PAD_LIST || CC_NV_Certify)
781 (COMMAND_ATTRIBUTES)(CC_NV_Certify * // 0x0184
782 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)),
783 #endif
784 #if (PAD_LIST || CC_EventSequenceComplete)
785 (COMMAND_ATTRIBUTES)(CC_EventSequenceComplete * // 0x0185
786 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER)),
787 #endif
788 #if (PAD_LIST || CC_HashSequenceStart)
789 (COMMAND_ATTRIBUTES)(CC_HashSequenceStart * // 0x0186
790 (IS_IMPLEMENTED+DECRYPT_2+R_HANDLE)),
791 #endif
792 #if (PAD_LIST || CC_PolicyPhysicalPresence)
793 (COMMAND_ATTRIBUTES)(CC_PolicyPhysicalPresence * // 0x0187
794 (IS_IMPLEMENTED+ALLOW_TRIAL)),
795 #endif
796 #if (PAD_LIST || CC_PolicyDuplicationSelect)
797 (COMMAND_ATTRIBUTES)(CC_PolicyDuplicationSelect * // 0x0188
798 (IS_IMPLEMENTED+DECRYPT_2+ALLOW_TRIAL)),
799 #endif
800 #if (PAD_LIST || CC_PolicyGetDigest)
801 (COMMAND_ATTRIBUTES)(CC_PolicyGetDigest * // 0x0189
802 (IS_IMPLEMENTED+ALLOW_TRIAL+ENCRYPT_2)),
803 #endif
804 #if (PAD_LIST || CC_TestParms)
805 (COMMAND_ATTRIBUTES)(CC_TestParms * // 0x018A
806 (IS_IMPLEMENTED)),
807 #endif
808 #if (PAD_LIST || CC_Commit)
809 (COMMAND_ATTRIBUTES)(CC_Commit * // 0x018B
810 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)),
811 #endif
812 #if (PAD_LIST || CC_PolicyPassword)
813 (COMMAND_ATTRIBUTES)(CC_PolicyPassword * // 0x018C
814 (IS_IMPLEMENTED+ALLOW_TRIAL)),
815 #endif
816 #if (PAD_LIST || CC_ZGen_2Phase)
817 (COMMAND_ATTRIBUTES)(CC_ZGen_2Phase * // 0x018D
818 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)),
819 #endif
820 #if (PAD_LIST || CC_EC_Ephemeral)
821 (COMMAND_ATTRIBUTES)(CC_EC_Ephemeral * // 0x018E
822 (IS_IMPLEMENTED+ENCRYPT_2)),
823 #endif
824 #if (PAD_LIST || CC_PolicyNvWritten)
825 (COMMAND_ATTRIBUTES)(CC_PolicyNvWritten * // 0x018F
826 (IS_IMPLEMENTED+ALLOW_TRIAL)),
827 #endif
828 #if (PAD_LIST || CC_PolicyTemplate)
829 (COMMAND_ATTRIBUTES)(CC_PolicyTemplate * // 0x0190
830 (IS_IMPLEMENTED+DECRYPT_2+ALLOW_TRIAL)),
831 #endif
832 #if (PAD_LIST || CC_CreateLoaded)
833 (COMMAND_ATTRIBUTES)(CC_CreateLoaded * // 0x0191
834 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND+ENCRYPT_2+R_HANDLE)),
835 #endif
836 #if (PAD_LIST || CC_PolicyAuthorizeNV)
837 (COMMAND_ATTRIBUTES)(CC_PolicyAuthorizeNV * // 0x0192
838 (IS_IMPLEMENTED+HANDLE_1_USER+ALLOW_TRIAL)),
839 #endif
840 #if (PAD_LIST || CC_EncryptDecrypt2)
841 (COMMAND_ATTRIBUTES)(CC_EncryptDecrypt2 * // 0x0193
842 (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)),
843 #endif
844 #if (PAD_LIST || CC_AC_GetCapability)
5.5 CommandAttributes.h
The attributes defined in this file are produced by the parser that creates the structure definitions from
Part 3. The attributes are defined in that parser and should track the attributes being tested in
CommandCodeAttributes.c. Generally, when an attribute is added to this list, new code will be needed in
CommandCodeAttributes.c to test it.
1 #ifndef COMMAND_ATTRIBUTES_H
2 #define COMMAND_ATTRIBUTES_H
3 typedef UINT16 COMMAND_ATTRIBUTES;
4 #define NOT_IMPLEMENTED (COMMAND_ATTRIBUTES)(0)
5 #define ENCRYPT_2 ((COMMAND_ATTRIBUTES)1 << 0)
6 #define ENCRYPT_4 ((COMMAND_ATTRIBUTES)1 << 1)
7 #define DECRYPT_2 ((COMMAND_ATTRIBUTES)1 << 2)
8 #define DECRYPT_4 ((COMMAND_ATTRIBUTES)1 << 3)
9 #define HANDLE_1_USER ((COMMAND_ATTRIBUTES)1 << 4)
10 #define HANDLE_1_ADMIN ((COMMAND_ATTRIBUTES)1 << 5)
11 #define HANDLE_1_DUP ((COMMAND_ATTRIBUTES)1 << 6)
12 #define HANDLE_2_USER ((COMMAND_ATTRIBUTES)1 << 7)
13 #define PP_COMMAND ((COMMAND_ATTRIBUTES)1 << 8)
14 #define IS_IMPLEMENTED ((COMMAND_ATTRIBUTES)1 << 9)
15 #define NO_SESSIONS ((COMMAND_ATTRIBUTES)1 << 10)
16 #define NV_COMMAND ((COMMAND_ATTRIBUTES)1 << 11)
17 #define PP_REQUIRED ((COMMAND_ATTRIBUTES)1 << 12)
18 #define R_HANDLE ((COMMAND_ATTRIBUTES)1 << 13)
19 #define ALLOW_TRIAL ((COMMAND_ATTRIBUTES)1 << 14)
20 #endif // COMMAND_ATTRIBUTES_H
5.6 CommandDispatchData.h
1 #ifdef _COMMAND_TABLE_DISPATCH_
These macros provide some variability in how the data is encoded. They also make the lines a little
shorter. ;-)
4 #if TABLE_DRIVEN_MARSHAL
5 # define UNMARSHAL_DISPATCH(name) (marshalIndex_t)name##_MARSHAL_REF
6 # define MARSHAL_DISPATCH(name) (marshalIndex_t)name##_MARSHAL_REF
7 # define _UNMARSHAL_T_ marshalIndex_t
8 # define _MARSHAL_T_ marshalIndex_t
9 #
10 #else
11 # define UNMARSHAL_DISPATCH(name) (UNMARSHAL_t)name##_Unmarshal
12 # define MARSHAL_DISPATCH(name) (MARSHAL_t)name##_Marshal
13 # define _UNMARSHAL_T_ UNMARSHAL_t
14 # define _MARSHAL_T_ MARSHAL_t
15 #endif
The UnmarshalArray() contains the dispatch functions for the unmarshaling code. The defines in this
array are used to make it easier to cross reference the unmarshaling values in the types array of each
command
113 UNMARSHAL_DISPATCH(TPMI_YES_NO),
114 #define TPML_ALG_P_UNMARSHAL (TPMI_YES_NO_P_UNMARSHAL + 1)
115 UNMARSHAL_DISPATCH(TPML_ALG),
116 #define TPML_CC_P_UNMARSHAL (TPML_ALG_P_UNMARSHAL + 1)
117 UNMARSHAL_DISPATCH(TPML_CC),
118 #define TPML_DIGEST_P_UNMARSHAL (TPML_CC_P_UNMARSHAL + 1)
119 UNMARSHAL_DISPATCH(TPML_DIGEST),
120 #define TPML_DIGEST_VALUES_P_UNMARSHAL (TPML_DIGEST_P_UNMARSHAL + 1)
121 UNMARSHAL_DISPATCH(TPML_DIGEST_VALUES),
122 #define TPML_PCR_SELECTION_P_UNMARSHAL (TPML_DIGEST_VALUES_P_UNMARSHAL + 1)
123 UNMARSHAL_DISPATCH(TPML_PCR_SELECTION),
124 #define TPMS_CONTEXT_P_UNMARSHAL (TPML_PCR_SELECTION_P_UNMARSHAL + 1)
125 UNMARSHAL_DISPATCH(TPMS_CONTEXT),
126 #define TPMT_PUBLIC_PARMS_P_UNMARSHAL (TPMS_CONTEXT_P_UNMARSHAL + 1)
127 UNMARSHAL_DISPATCH(TPMT_PUBLIC_PARMS),
128 #define TPMT_TK_AUTH_P_UNMARSHAL (TPMT_PUBLIC_PARMS_P_UNMARSHAL + 1)
129 UNMARSHAL_DISPATCH(TPMT_TK_AUTH),
130 #define TPMT_TK_CREATION_P_UNMARSHAL (TPMT_TK_AUTH_P_UNMARSHAL + 1)
131 UNMARSHAL_DISPATCH(TPMT_TK_CREATION),
132 #define TPMT_TK_HASHCHECK_P_UNMARSHAL (TPMT_TK_CREATION_P_UNMARSHAL + 1)
133 UNMARSHAL_DISPATCH(TPMT_TK_HASHCHECK),
134 #define TPMT_TK_VERIFIED_P_UNMARSHAL (TPMT_TK_HASHCHECK_P_UNMARSHAL + 1)
135 UNMARSHAL_DISPATCH(TPMT_TK_VERIFIED),
136 #define TPM_AT_P_UNMARSHAL (TPMT_TK_VERIFIED_P_UNMARSHAL + 1)
137 UNMARSHAL_DISPATCH(TPM_AT),
138 #define TPM_CAP_P_UNMARSHAL (TPM_AT_P_UNMARSHAL + 1)
139 UNMARSHAL_DISPATCH(TPM_CAP),
140 #define TPM_CLOCK_ADJUST_P_UNMARSHAL (TPM_CAP_P_UNMARSHAL + 1)
141 UNMARSHAL_DISPATCH(TPM_CLOCK_ADJUST),
142 #define TPM_EO_P_UNMARSHAL (TPM_CLOCK_ADJUST_P_UNMARSHAL + 1)
143 UNMARSHAL_DISPATCH(TPM_EO),
144 #define TPM_SE_P_UNMARSHAL (TPM_EO_P_UNMARSHAL + 1)
145 UNMARSHAL_DISPATCH(TPM_SE),
146 #define TPM_SU_P_UNMARSHAL (TPM_SE_P_UNMARSHAL + 1)
147 UNMARSHAL_DISPATCH(TPM_SU),
148 #define UINT16_P_UNMARSHAL (TPM_SU_P_UNMARSHAL + 1)
149 UNMARSHAL_DISPATCH(UINT16),
150 #define UINT32_P_UNMARSHAL (UINT16_P_UNMARSHAL + 1)
151 UNMARSHAL_DISPATCH(UINT32),
152 #define UINT64_P_UNMARSHAL (UINT32_P_UNMARSHAL + 1)
153 UNMARSHAL_DISPATCH(UINT64),
154 #define UINT8_P_UNMARSHAL (UINT64_P_UNMARSHAL + 1)
155 UNMARSHAL_DISPATCH(UINT8),
156 // PARAMETER_FIRST_FLAG_TYPE is the first parameter to need a flag.
157 #define PARAMETER_FIRST_FLAG_TYPE (UINT8_P_UNMARSHAL + 1)
158 #define TPM2B_PUBLIC_P_UNMARSHAL (UINT8_P_UNMARSHAL + 1)
159 UNMARSHAL_DISPATCH(TPM2B_PUBLIC),
160 #define TPMI_ALG_CIPHER_MODE_P_UNMARSHAL (TPM2B_PUBLIC_P_UNMARSHAL + 1)
161 UNMARSHAL_DISPATCH(TPMI_ALG_CIPHER_MODE),
162 #define TPMI_ALG_HASH_P_UNMARSHAL \
163 (TPMI_ALG_CIPHER_MODE_P_UNMARSHAL + 1)
164 UNMARSHAL_DISPATCH(TPMI_ALG_HASH),
165 #define TPMI_ALG_MAC_SCHEME_P_UNMARSHAL (TPMI_ALG_HASH_P_UNMARSHAL + 1)
166 UNMARSHAL_DISPATCH(TPMI_ALG_MAC_SCHEME),
167 #define TPMI_DH_PCR_P_UNMARSHAL \
168 (TPMI_ALG_MAC_SCHEME_P_UNMARSHAL + 1)
169 UNMARSHAL_DISPATCH(TPMI_DH_PCR),
170 #define TPMI_ECC_KEY_EXCHANGE_P_UNMARSHAL (TPMI_DH_PCR_P_UNMARSHAL + 1)
171 UNMARSHAL_DISPATCH(TPMI_ECC_KEY_EXCHANGE),
172 #define TPMI_RH_ENABLES_P_UNMARSHAL \
173 (TPMI_ECC_KEY_EXCHANGE_P_UNMARSHAL + 1)
174 UNMARSHAL_DISPATCH(TPMI_RH_ENABLES),
175 #define TPMI_RH_HIERARCHY_P_UNMARSHAL (TPMI_RH_ENABLES_P_UNMARSHAL + 1)
176 UNMARSHAL_DISPATCH(TPMI_RH_HIERARCHY),
177 #define TPMT_RSA_DECRYPT_P_UNMARSHAL (TPMI_RH_HIERARCHY_P_UNMARSHAL + 1)
178 UNMARSHAL_DISPATCH(TPMT_RSA_DECRYPT),
The MarshalArray() contains the dispatch functions for the marshaling code. The defines in this array are
used to make it easier to cross reference the marshaling values in the types array of each command
240 MARSHAL_DISPATCH(TPML_DIGEST_VALUES),
241 #define TPML_PCR_SELECTION_P_MARSHAL (TPML_DIGEST_VALUES_P_MARSHAL + 1)
242 MARSHAL_DISPATCH(TPML_PCR_SELECTION),
243 #define TPMS_AC_OUTPUT_P_MARSHAL (TPML_PCR_SELECTION_P_MARSHAL + 1)
244 MARSHAL_DISPATCH(TPMS_AC_OUTPUT),
245 #define TPMS_ALGORITHM_DETAIL_ECC_P_MARSHAL (TPMS_AC_OUTPUT_P_MARSHAL + 1)
246 MARSHAL_DISPATCH(TPMS_ALGORITHM_DETAIL_ECC),
247 #define TPMS_CAPABILITY_DATA_P_MARSHAL \
248 (TPMS_ALGORITHM_DETAIL_ECC_P_MARSHAL + 1)
249 MARSHAL_DISPATCH(TPMS_CAPABILITY_DATA),
250 #define TPMS_CONTEXT_P_MARSHAL (TPMS_CAPABILITY_DATA_P_MARSHAL + 1)
251 MARSHAL_DISPATCH(TPMS_CONTEXT),
252 #define TPMS_TIME_INFO_P_MARSHAL (TPMS_CONTEXT_P_MARSHAL + 1)
253 MARSHAL_DISPATCH(TPMS_TIME_INFO),
254 #define TPMT_HA_P_MARSHAL (TPMS_TIME_INFO_P_MARSHAL + 1)
255 MARSHAL_DISPATCH(TPMT_HA),
256 #define TPMT_SIGNATURE_P_MARSHAL (TPMT_HA_P_MARSHAL + 1)
257 MARSHAL_DISPATCH(TPMT_SIGNATURE),
258 #define TPMT_TK_AUTH_P_MARSHAL (TPMT_SIGNATURE_P_MARSHAL + 1)
259 MARSHAL_DISPATCH(TPMT_TK_AUTH),
260 #define TPMT_TK_CREATION_P_MARSHAL (TPMT_TK_AUTH_P_MARSHAL + 1)
261 MARSHAL_DISPATCH(TPMT_TK_CREATION),
262 #define TPMT_TK_HASHCHECK_P_MARSHAL (TPMT_TK_CREATION_P_MARSHAL + 1)
263 MARSHAL_DISPATCH(TPMT_TK_HASHCHECK),
264 #define TPMT_TK_VERIFIED_P_MARSHAL (TPMT_TK_HASHCHECK_P_MARSHAL + 1)
265 MARSHAL_DISPATCH(TPMT_TK_VERIFIED),
266 #define UINT32_P_MARSHAL (TPMT_TK_VERIFIED_P_MARSHAL + 1)
267 MARSHAL_DISPATCH(UINT32),
268 #define UINT16_P_MARSHAL (UINT32_P_MARSHAL + 1)
269 MARSHAL_DISPATCH(UINT16)
270 // RESPONSE_PARAMETER_LAST_TYPE is the end of the response parameter list.
271 #define RESPONSE_PARAMETER_LAST_TYPE (UINT16_P_MARSHAL)
272 };
This list of aliases allows the types in the _COMMAND_DESCRIPTOR_T to match the types in the
command/response templates of part 3.
301 /* outSize */ 0,
302 /* offsetOfTypes */ offsetof(Startup_COMMAND_DESCRIPTOR_t, types),
303 /* offsets */ // No parameter offsets;
304 /* types */ {TPM_SU_P_UNMARSHAL,
305 END_OF_LIST,
306 END_OF_LIST}
307 };
308 #define _StartupDataAddress (&_StartupData)
309 #else
310 #define _StartupDataAddress 0
311 #endif // CC_Startup
312 #if CC_Shutdown
313 #include "Shutdown_fp.h"
314 typedef TPM_RC (Shutdown_Entry)(
315 Shutdown_In *in
316 );
317 typedef const struct {
318 Shutdown_Entry *entry;
319 UINT16 inSize;
320 UINT16 outSize;
321 UINT16 offsetOfTypes;
322 BYTE types[3];
323 } Shutdown_COMMAND_DESCRIPTOR_t;
324 Shutdown_COMMAND_DESCRIPTOR_t _ShutdownData = {
325 /* entry */ &TPM2_Shutdown,
326 /* inSize */ (UINT16)(sizeof(Shutdown_In)),
327 /* outSize */ 0,
328 /* offsetOfTypes */ offsetof(Shutdown_COMMAND_DESCRIPTOR_t, types),
329 /* offsets */ // No parameter offsets;
330 /* types */ {TPM_SU_P_UNMARSHAL,
331 END_OF_LIST,
332 END_OF_LIST}
333 };
334 #define _ShutdownDataAddress (&_ShutdownData)
335 #else
336 #define _ShutdownDataAddress 0
337 #endif // CC_Shutdown
338 #if CC_SelfTest
339 #include "SelfTest_fp.h"
340 typedef TPM_RC (SelfTest_Entry)(
341 SelfTest_In *in
342 );
343 typedef const struct {
344 SelfTest_Entry *entry;
345 UINT16 inSize;
346 UINT16 outSize;
347 UINT16 offsetOfTypes;
348 BYTE types[3];
349 } SelfTest_COMMAND_DESCRIPTOR_t;
350 SelfTest_COMMAND_DESCRIPTOR_t _SelfTestData = {
351 /* entry */ &TPM2_SelfTest,
352 /* inSize */ (UINT16)(sizeof(SelfTest_In)),
353 /* outSize */ 0,
354 /* offsetOfTypes */ offsetof(SelfTest_COMMAND_DESCRIPTOR_t, types),
355 /* offsets */ // No parameter offsets;
356 /* types */ {TPMI_YES_NO_P_UNMARSHAL,
357 END_OF_LIST,
358 END_OF_LIST}
359 };
360 #define _SelfTestDataAddress (&_SelfTestData)
361 #else
362 #define _SelfTestDataAddress 0
363 #endif // CC_SelfTest
364 #if CC_IncrementalSelfTest
365 #include "IncrementalSelfTest_fp.h"
366 typedef TPM_RC (IncrementalSelfTest_Entry)(
694 END_OF_LIST}
695 };
696 #define _MakeCredentialDataAddress (&_MakeCredentialData)
697 #else
698 #define _MakeCredentialDataAddress 0
699 #endif // CC_MakeCredential
700 #if CC_Unseal
701 #include "Unseal_fp.h"
702 typedef TPM_RC (Unseal_Entry)(
703 Unseal_In *in,
704 Unseal_Out *out
705 );
706 typedef const struct {
707 Unseal_Entry *entry;
708 UINT16 inSize;
709 UINT16 outSize;
710 UINT16 offsetOfTypes;
711 BYTE types[4];
712 } Unseal_COMMAND_DESCRIPTOR_t;
713 Unseal_COMMAND_DESCRIPTOR_t _UnsealData = {
714 /* entry */ &TPM2_Unseal,
715 /* inSize */ (UINT16)(sizeof(Unseal_In)),
716 /* outSize */ (UINT16)(sizeof(Unseal_Out)),
717 /* offsetOfTypes */ offsetof(Unseal_COMMAND_DESCRIPTOR_t, types),
718 /* offsets */ // No parameter offsets;
719 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
720 END_OF_LIST,
721 TPM2B_SENSITIVE_DATA_P_MARSHAL,
722 END_OF_LIST}
723 };
724 #define _UnsealDataAddress (&_UnsealData)
725 #else
726 #define _UnsealDataAddress 0
727 #endif // CC_Unseal
728 #if CC_ObjectChangeAuth
729 #include "ObjectChangeAuth_fp.h"
730 typedef TPM_RC (ObjectChangeAuth_Entry)(
731 ObjectChangeAuth_In *in,
732 ObjectChangeAuth_Out *out
733 );
734 typedef const struct {
735 ObjectChangeAuth_Entry *entry;
736 UINT16 inSize;
737 UINT16 outSize;
738 UINT16 offsetOfTypes;
739 UINT16 paramOffsets[2];
740 BYTE types[6];
741 } ObjectChangeAuth_COMMAND_DESCRIPTOR_t;
742 ObjectChangeAuth_COMMAND_DESCRIPTOR_t _ObjectChangeAuthData = {
743 /* entry */ &TPM2_ObjectChangeAuth,
744 /* inSize */ (UINT16)(sizeof(ObjectChangeAuth_In)),
745 /* outSize */ (UINT16)(sizeof(ObjectChangeAuth_Out)),
746 /* offsetOfTypes */ offsetof(ObjectChangeAuth_COMMAND_DESCRIPTOR_t, types),
747 /* offsets */ {(UINT16)(offsetof(ObjectChangeAuth_In, parentHandle)),
748 (UINT16)(offsetof(ObjectChangeAuth_In, newAuth))},
749 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
750 TPMI_DH_OBJECT_H_UNMARSHAL,
751 TPM2B_AUTH_P_UNMARSHAL,
752 END_OF_LIST,
753 TPM2B_PRIVATE_P_MARSHAL,
754 END_OF_LIST}
755 };
756 #define _ObjectChangeAuthDataAddress (&_ObjectChangeAuthData)
757 #else
758 #define _ObjectChangeAuthDataAddress 0
759 #endif // CC_ObjectChangeAuth
826 END_OF_LIST,
827 TPM2B_DATA_P_MARSHAL,
828 TPM2B_PRIVATE_P_MARSHAL,
829 TPM2B_ENCRYPTED_SECRET_P_MARSHAL,
830 END_OF_LIST}
831 };
832 #define _DuplicateDataAddress (&_DuplicateData)
833 #else
834 #define _DuplicateDataAddress 0
835 #endif // CC_Duplicate
836 #if CC_Rewrap
837 #include "Rewrap_fp.h"
838 typedef TPM_RC (Rewrap_Entry)(
839 Rewrap_In *in,
840 Rewrap_Out *out
841 );
842 typedef const struct {
843 Rewrap_Entry *entry;
844 UINT16 inSize;
845 UINT16 outSize;
846 UINT16 offsetOfTypes;
847 UINT16 paramOffsets[5];
848 BYTE types[9];
849 } Rewrap_COMMAND_DESCRIPTOR_t;
850 Rewrap_COMMAND_DESCRIPTOR_t _RewrapData = {
851 /* entry */ &TPM2_Rewrap,
852 /* inSize */ (UINT16)(sizeof(Rewrap_In)),
853 /* outSize */ (UINT16)(sizeof(Rewrap_Out)),
854 /* offsetOfTypes */ offsetof(Rewrap_COMMAND_DESCRIPTOR_t, types),
855 /* offsets */ {(UINT16)(offsetof(Rewrap_In, newParent)),
856 (UINT16)(offsetof(Rewrap_In, inDuplicate)),
857 (UINT16)(offsetof(Rewrap_In, name)),
858 (UINT16)(offsetof(Rewrap_In, inSymSeed)),
859 (UINT16)(offsetof(Rewrap_Out, outSymSeed))},
860 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL + ADD_FLAG,
861 TPMI_DH_OBJECT_H_UNMARSHAL + ADD_FLAG,
862 TPM2B_PRIVATE_P_UNMARSHAL,
863 TPM2B_NAME_P_UNMARSHAL,
864 TPM2B_ENCRYPTED_SECRET_P_UNMARSHAL,
865 END_OF_LIST,
866 TPM2B_PRIVATE_P_MARSHAL,
867 TPM2B_ENCRYPTED_SECRET_P_MARSHAL,
868 END_OF_LIST}
869 };
870 #define _RewrapDataAddress (&_RewrapData)
871 #else
872 #define _RewrapDataAddress 0
873 #endif // CC_Rewrap
874 #if CC_Import
875 #include "Import_fp.h"
876 typedef TPM_RC (Import_Entry)(
877 Import_In *in,
878 Import_Out *out
879 );
880 typedef const struct {
881 Import_Entry *entry;
882 UINT16 inSize;
883 UINT16 outSize;
884 UINT16 offsetOfTypes;
885 UINT16 paramOffsets[5];
886 BYTE types[9];
887 } Import_COMMAND_DESCRIPTOR_t;
888 Import_COMMAND_DESCRIPTOR_t _ImportData = {
889 /* entry */ &TPM2_Import,
890 /* inSize */ (UINT16)(sizeof(Import_In)),
891 /* outSize */ (UINT16)(sizeof(Import_Out)),
1485 };
1486 #define _SequenceCompleteDataAddress (&_SequenceCompleteData)
1487 #else
1488 #define _SequenceCompleteDataAddress 0
1489 #endif // CC_SequenceComplete
1490 #if CC_EventSequenceComplete
1491 #include "EventSequenceComplete_fp.h"
1492 typedef TPM_RC (EventSequenceComplete_Entry)(
1493 EventSequenceComplete_In *in,
1494 EventSequenceComplete_Out *out
1495 );
1496 typedef const struct {
1497 EventSequenceComplete_Entry *entry;
1498 UINT16 inSize;
1499 UINT16 outSize;
1500 UINT16 offsetOfTypes;
1501 UINT16 paramOffsets[2];
1502 BYTE types[6];
1503 } EventSequenceComplete_COMMAND_DESCRIPTOR_t;
1504 EventSequenceComplete_COMMAND_DESCRIPTOR_t _EventSequenceCompleteData = {
1505 /* entry */ &TPM2_EventSequenceComplete,
1506 /* inSize */ (UINT16)(sizeof(EventSequenceComplete_In)),
1507 /* outSize */ (UINT16)(sizeof(EventSequenceComplete_Out)),
1508 /* offsetOfTypes */
offsetof(EventSequenceComplete_COMMAND_DESCRIPTOR_t, types),
1509 /* offsets */ {(UINT16)(offsetof(EventSequenceComplete_In,
sequenceHandle)),
1510 (UINT16)(offsetof(EventSequenceComplete_In,
buffer))},
1511 /* types */ {TPMI_DH_PCR_H_UNMARSHAL + ADD_FLAG,
1512 TPMI_DH_OBJECT_H_UNMARSHAL,
1513 TPM2B_MAX_BUFFER_P_UNMARSHAL,
1514 END_OF_LIST,
1515 TPML_DIGEST_VALUES_P_MARSHAL,
1516 END_OF_LIST}
1517 };
1518 #define _EventSequenceCompleteDataAddress (&_EventSequenceCompleteData)
1519 #else
1520 #define _EventSequenceCompleteDataAddress 0
1521 #endif // CC_EventSequenceComplete
1522 #if CC_Certify
1523 #include "Certify_fp.h"
1524 typedef TPM_RC (Certify_Entry)(
1525 Certify_In *in,
1526 Certify_Out *out
1527 );
1528 typedef const struct {
1529 Certify_Entry *entry;
1530 UINT16 inSize;
1531 UINT16 outSize;
1532 UINT16 offsetOfTypes;
1533 UINT16 paramOffsets[4];
1534 BYTE types[8];
1535 } Certify_COMMAND_DESCRIPTOR_t;
1536 Certify_COMMAND_DESCRIPTOR_t _CertifyData = {
1537 /* entry */ &TPM2_Certify,
1538 /* inSize */ (UINT16)(sizeof(Certify_In)),
1539 /* outSize */ (UINT16)(sizeof(Certify_Out)),
1540 /* offsetOfTypes */ offsetof(Certify_COMMAND_DESCRIPTOR_t, types),
1541 /* offsets */ {(UINT16)(offsetof(Certify_In, signHandle)),
1542 (UINT16)(offsetof(Certify_In, qualifyingData)),
1543 (UINT16)(offsetof(Certify_In, inScheme)),
1544 (UINT16)(offsetof(Certify_Out, signature))},
1545 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
1546 TPMI_DH_OBJECT_H_UNMARSHAL + ADD_FLAG,
1547 TPM2B_DATA_P_UNMARSHAL,
1735 END_OF_LIST,
1736 TPM2B_ATTEST_P_MARSHAL,
1737 TPMT_SIGNATURE_P_MARSHAL,
1738 END_OF_LIST}
1739 };
1740 #define _GetTimeDataAddress (&_GetTimeData)
1741 #else
1742 #define _GetTimeDataAddress 0
1743 #endif // CC_GetTime
1744 #if CC_CertifyX509
1745 #include "CertifyX509_fp.h"
1746 typedef TPM_RC (CertifyX509_Entry)(
1747 CertifyX509_In *in,
1748 CertifyX509_Out *out
1749 );
1750 typedef const struct {
1751 CertifyX509_Entry *entry;
1752 UINT16 inSize;
1753 UINT16 outSize;
1754 UINT16 offsetOfTypes;
1755 UINT16 paramOffsets[6];
1756 BYTE types[10];
1757 } CertifyX509_COMMAND_DESCRIPTOR_t;
1758 CertifyX509_COMMAND_DESCRIPTOR_t _CertifyX509Data = {
1759 /* entry */ &TPM2_CertifyX509,
1760 /* inSize */ (UINT16)(sizeof(CertifyX509_In)),
1761 /* outSize */ (UINT16)(sizeof(CertifyX509_Out)),
1762 /* offsetOfTypes */ offsetof(CertifyX509_COMMAND_DESCRIPTOR_t, types),
1763 /* offsets */ {(UINT16)(offsetof(CertifyX509_In, signHandle)),
1764 (UINT16)(offsetof(CertifyX509_In, reserved)),
1765 (UINT16)(offsetof(CertifyX509_In, inScheme)),
1766 (UINT16)(offsetof(CertifyX509_In, partialCertificate)),
1767 (UINT16)(offsetof(CertifyX509_Out, tbsDigest)),
1768 (UINT16)(offsetof(CertifyX509_Out, signature))},
1769 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
1770 TPMI_DH_OBJECT_H_UNMARSHAL + ADD_FLAG,
1771 TPM2B_DATA_P_UNMARSHAL,
1772 TPMT_SIG_SCHEME_P_UNMARSHAL + ADD_FLAG,
1773 TPM2B_MAX_BUFFER_P_UNMARSHAL,
1774 END_OF_LIST,
1775 TPM2B_MAX_BUFFER_P_MARSHAL,
1776 TPM2B_DIGEST_P_MARSHAL,
1777 TPMT_SIGNATURE_P_MARSHAL,
1778 END_OF_LIST}
1779 };
1780 #define _CertifyX509DataAddress (&_CertifyX509Data)
1781 #else
1782 #define _CertifyX509DataAddress 0
1783 #endif // CC_CertifyX509
1784 #if CC_Commit
1785 #include "Commit_fp.h"
1786 typedef TPM_RC (Commit_Entry)(
1787 Commit_In *in,
1788 Commit_Out *out
1789 );
1790 typedef const struct {
1791 Commit_Entry *entry;
1792 UINT16 inSize;
1793 UINT16 outSize;
1794 UINT16 offsetOfTypes;
1795 UINT16 paramOffsets[6];
1796 BYTE types[10];
1797 } Commit_COMMAND_DESCRIPTOR_t;
1798 Commit_COMMAND_DESCRIPTOR_t _CommitData = {
1799 /* entry */ &TPM2_Commit,
1800 /* inSize */ (UINT16)(sizeof(Commit_In)),
1867 } VerifySignature_COMMAND_DESCRIPTOR_t;
1868 VerifySignature_COMMAND_DESCRIPTOR_t _VerifySignatureData = {
1869 /* entry */ &TPM2_VerifySignature,
1870 /* inSize */ (UINT16)(sizeof(VerifySignature_In)),
1871 /* outSize */ (UINT16)(sizeof(VerifySignature_Out)),
1872 /* offsetOfTypes */ offsetof(VerifySignature_COMMAND_DESCRIPTOR_t, types),
1873 /* offsets */ {(UINT16)(offsetof(VerifySignature_In, digest)),
1874 (UINT16)(offsetof(VerifySignature_In, signature))},
1875 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
1876 TPM2B_DIGEST_P_UNMARSHAL,
1877 TPMT_SIGNATURE_P_UNMARSHAL,
1878 END_OF_LIST,
1879 TPMT_TK_VERIFIED_P_MARSHAL,
1880 END_OF_LIST}
1881 };
1882 #define _VerifySignatureDataAddress (&_VerifySignatureData)
1883 #else
1884 #define _VerifySignatureDataAddress 0
1885 #endif // CC_VerifySignature
1886 #if CC_Sign
1887 #include "Sign_fp.h"
1888 typedef TPM_RC (Sign_Entry)(
1889 Sign_In *in,
1890 Sign_Out *out
1891 );
1892 typedef const struct {
1893 Sign_Entry *entry;
1894 UINT16 inSize;
1895 UINT16 outSize;
1896 UINT16 offsetOfTypes;
1897 UINT16 paramOffsets[3];
1898 BYTE types[7];
1899 } Sign_COMMAND_DESCRIPTOR_t;
1900 Sign_COMMAND_DESCRIPTOR_t _SignData = {
1901 /* entry */ &TPM2_Sign,
1902 /* inSize */ (UINT16)(sizeof(Sign_In)),
1903 /* outSize */ (UINT16)(sizeof(Sign_Out)),
1904 /* offsetOfTypes */ offsetof(Sign_COMMAND_DESCRIPTOR_t, types),
1905 /* offsets */ {(UINT16)(offsetof(Sign_In, digest)),
1906 (UINT16)(offsetof(Sign_In, inScheme)),
1907 (UINT16)(offsetof(Sign_In, validation))},
1908 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
1909 TPM2B_DIGEST_P_UNMARSHAL,
1910 TPMT_SIG_SCHEME_P_UNMARSHAL + ADD_FLAG,
1911 TPMT_TK_HASHCHECK_P_UNMARSHAL,
1912 END_OF_LIST,
1913 TPMT_SIGNATURE_P_MARSHAL,
1914 END_OF_LIST}
1915 };
1916 #define _SignDataAddress (&_SignData)
1917 #else
1918 #define _SignDataAddress 0
1919 #endif // CC_Sign
1920 #if CC_SetCommandCodeAuditStatus
1921 #include "SetCommandCodeAuditStatus_fp.h"
1922 typedef TPM_RC (SetCommandCodeAuditStatus_Entry)(
1923 SetCommandCodeAuditStatus_In *in
1924 );
1925 typedef const struct {
1926 SetCommandCodeAuditStatus_Entry *entry;
1927 UINT16 inSize;
1928 UINT16 outSize;
1929 UINT16 offsetOfTypes;
1930 UINT16 paramOffsets[3];
1931 BYTE types[6];
1932 } SetCommandCodeAuditStatus_COMMAND_DESCRIPTOR_t;
2191 TPMI_SH_POLICY_H_UNMARSHAL,
2192 TPM2B_NONCE_P_UNMARSHAL,
2193 TPM2B_DIGEST_P_UNMARSHAL,
2194 TPM2B_NONCE_P_UNMARSHAL,
2195 INT32_P_UNMARSHAL,
2196 TPMT_SIGNATURE_P_UNMARSHAL,
2197 END_OF_LIST,
2198 TPM2B_TIMEOUT_P_MARSHAL,
2199 TPMT_TK_AUTH_P_MARSHAL,
2200 END_OF_LIST}
2201 };
2202 #define _PolicySignedDataAddress (&_PolicySignedData)
2203 #else
2204 #define _PolicySignedDataAddress 0
2205 #endif // CC_PolicySigned
2206 #if CC_PolicySecret
2207 #include "PolicySecret_fp.h"
2208 typedef TPM_RC (PolicySecret_Entry)(
2209 PolicySecret_In *in,
2210 PolicySecret_Out *out
2211 );
2212 typedef const struct {
2213 PolicySecret_Entry *entry;
2214 UINT16 inSize;
2215 UINT16 outSize;
2216 UINT16 offsetOfTypes;
2217 UINT16 paramOffsets[6];
2218 BYTE types[10];
2219 } PolicySecret_COMMAND_DESCRIPTOR_t;
2220 PolicySecret_COMMAND_DESCRIPTOR_t _PolicySecretData = {
2221 /* entry */ &TPM2_PolicySecret,
2222 /* inSize */ (UINT16)(sizeof(PolicySecret_In)),
2223 /* outSize */ (UINT16)(sizeof(PolicySecret_Out)),
2224 /* offsetOfTypes */ offsetof(PolicySecret_COMMAND_DESCRIPTOR_t, types),
2225 /* offsets */ {(UINT16)(offsetof(PolicySecret_In, policySession)),
2226 (UINT16)(offsetof(PolicySecret_In, nonceTPM)),
2227 (UINT16)(offsetof(PolicySecret_In, cpHashA)),
2228 (UINT16)(offsetof(PolicySecret_In, policyRef)),
2229 (UINT16)(offsetof(PolicySecret_In, expiration)),
2230 (UINT16)(offsetof(PolicySecret_Out, policyTicket))},
2231 /* types */ {TPMI_DH_ENTITY_H_UNMARSHAL,
2232 TPMI_SH_POLICY_H_UNMARSHAL,
2233 TPM2B_NONCE_P_UNMARSHAL,
2234 TPM2B_DIGEST_P_UNMARSHAL,
2235 TPM2B_NONCE_P_UNMARSHAL,
2236 INT32_P_UNMARSHAL,
2237 END_OF_LIST,
2238 TPM2B_TIMEOUT_P_MARSHAL,
2239 TPMT_TK_AUTH_P_MARSHAL,
2240 END_OF_LIST}
2241 };
2242 #define _PolicySecretDataAddress (&_PolicySecretData)
2243 #else
2244 #define _PolicySecretDataAddress 0
2245 #endif // CC_PolicySecret
2246 #if CC_PolicyTicket
2247 #include "PolicyTicket_fp.h"
2248 typedef TPM_RC (PolicyTicket_Entry)(
2249 PolicyTicket_In *in
2250 );
2251 typedef const struct {
2252 PolicyTicket_Entry *entry;
2253 UINT16 inSize;
2254 UINT16 outSize;
2255 UINT16 offsetOfTypes;
2256 UINT16 paramOffsets[5];
2775 #else
2776 #define _PolicyAuthorizeNVDataAddress 0
2777 #endif // CC_PolicyAuthorizeNV
2778 #if CC_CreatePrimary
2779 #include "CreatePrimary_fp.h"
2780 typedef TPM_RC (CreatePrimary_Entry)(
2781 CreatePrimary_In *in,
2782 CreatePrimary_Out *out
2783 );
2784 typedef const struct {
2785 CreatePrimary_Entry *entry;
2786 UINT16 inSize;
2787 UINT16 outSize;
2788 UINT16 offsetOfTypes;
2789 UINT16 paramOffsets[9];
2790 BYTE types[13];
2791 } CreatePrimary_COMMAND_DESCRIPTOR_t;
2792 CreatePrimary_COMMAND_DESCRIPTOR_t _CreatePrimaryData = {
2793 /* entry */ &TPM2_CreatePrimary,
2794 /* inSize */ (UINT16)(sizeof(CreatePrimary_In)),
2795 /* outSize */ (UINT16)(sizeof(CreatePrimary_Out)),
2796 /* offsetOfTypes */ offsetof(CreatePrimary_COMMAND_DESCRIPTOR_t, types),
2797 /* offsets */ {(UINT16)(offsetof(CreatePrimary_In, inSensitive)),
2798 (UINT16)(offsetof(CreatePrimary_In, inPublic)),
2799 (UINT16)(offsetof(CreatePrimary_In, outsideInfo)),
2800 (UINT16)(offsetof(CreatePrimary_In, creationPCR)),
2801 (UINT16)(offsetof(CreatePrimary_Out, outPublic)),
2802 (UINT16)(offsetof(CreatePrimary_Out, creationData)),
2803 (UINT16)(offsetof(CreatePrimary_Out, creationHash)),
2804 (UINT16)(offsetof(CreatePrimary_Out, creationTicket)),
2805 (UINT16)(offsetof(CreatePrimary_Out, name))},
2806 /* types */ {TPMI_RH_HIERARCHY_H_UNMARSHAL + ADD_FLAG,
2807 TPM2B_SENSITIVE_CREATE_P_UNMARSHAL,
2808 TPM2B_PUBLIC_P_UNMARSHAL,
2809 TPM2B_DATA_P_UNMARSHAL,
2810 TPML_PCR_SELECTION_P_UNMARSHAL,
2811 END_OF_LIST,
2812 TPM_HANDLE_H_MARSHAL,
2813 TPM2B_PUBLIC_P_MARSHAL,
2814 TPM2B_CREATION_DATA_P_MARSHAL,
2815 TPM2B_DIGEST_P_MARSHAL,
2816 TPMT_TK_CREATION_P_MARSHAL,
2817 TPM2B_NAME_P_MARSHAL,
2818 END_OF_LIST}
2819 };
2820 #define _CreatePrimaryDataAddress (&_CreatePrimaryData)
2821 #else
2822 #define _CreatePrimaryDataAddress 0
2823 #endif // CC_CreatePrimary
2824 #if CC_HierarchyControl
2825 #include "HierarchyControl_fp.h"
2826 typedef TPM_RC (HierarchyControl_Entry)(
2827 HierarchyControl_In *in
2828 );
2829 typedef const struct {
2830 HierarchyControl_Entry *entry;
2831 UINT16 inSize;
2832 UINT16 outSize;
2833 UINT16 offsetOfTypes;
2834 UINT16 paramOffsets[2];
2835 BYTE types[5];
2836 } HierarchyControl_COMMAND_DESCRIPTOR_t;
2837 HierarchyControl_COMMAND_DESCRIPTOR_t _HierarchyControlData = {
2838 /* entry */ &TPM2_HierarchyControl,
2839 /* inSize */ (UINT16)(sizeof(HierarchyControl_In)),
2840 /* outSize */ 0,
2907 #else
2908 #define _ChangePPSDataAddress 0
2909 #endif // CC_ChangePPS
2910 #if CC_ChangeEPS
2911 #include "ChangeEPS_fp.h"
2912 typedef TPM_RC (ChangeEPS_Entry)(
2913 ChangeEPS_In *in
2914 );
2915 typedef const struct {
2916 ChangeEPS_Entry *entry;
2917 UINT16 inSize;
2918 UINT16 outSize;
2919 UINT16 offsetOfTypes;
2920 BYTE types[3];
2921 } ChangeEPS_COMMAND_DESCRIPTOR_t;
2922 ChangeEPS_COMMAND_DESCRIPTOR_t _ChangeEPSData = {
2923 /* entry */ &TPM2_ChangeEPS,
2924 /* inSize */ (UINT16)(sizeof(ChangeEPS_In)),
2925 /* outSize */ 0,
2926 /* offsetOfTypes */ offsetof(ChangeEPS_COMMAND_DESCRIPTOR_t, types),
2927 /* offsets */ // No parameter offsets;
2928 /* types */ {TPMI_RH_PLATFORM_H_UNMARSHAL,
2929 END_OF_LIST,
2930 END_OF_LIST}
2931 };
2932 #define _ChangeEPSDataAddress (&_ChangeEPSData)
2933 #else
2934 #define _ChangeEPSDataAddress 0
2935 #endif // CC_ChangeEPS
2936 #if CC_Clear
2937 #include "Clear_fp.h"
2938 typedef TPM_RC (Clear_Entry)(
2939 Clear_In *in
2940 );
2941 typedef const struct {
2942 Clear_Entry *entry;
2943 UINT16 inSize;
2944 UINT16 outSize;
2945 UINT16 offsetOfTypes;
2946 BYTE types[3];
2947 } Clear_COMMAND_DESCRIPTOR_t;
2948 Clear_COMMAND_DESCRIPTOR_t _ClearData = {
2949 /* entry */ &TPM2_Clear,
2950 /* inSize */ (UINT16)(sizeof(Clear_In)),
2951 /* outSize */ 0,
2952 /* offsetOfTypes */ offsetof(Clear_COMMAND_DESCRIPTOR_t, types),
2953 /* offsets */ // No parameter offsets;
2954 /* types */ {TPMI_RH_CLEAR_H_UNMARSHAL,
2955 END_OF_LIST,
2956 END_OF_LIST}
2957 };
2958 #define _ClearDataAddress (&_ClearData)
2959 #else
2960 #define _ClearDataAddress 0
2961 #endif // CC_Clear
2962 #if CC_ClearControl
2963 #include "ClearControl_fp.h"
2964 typedef TPM_RC (ClearControl_Entry)(
2965 ClearControl_In *in
2966 );
2967 typedef const struct {
2968 ClearControl_Entry *entry;
2969 UINT16 inSize;
2970 UINT16 outSize;
2971 UINT16 offsetOfTypes;
2972 UINT16 paramOffsets[1];
3160 END_OF_LIST}
3161 };
3162 #define _FieldUpgradeStartDataAddress (&_FieldUpgradeStartData)
3163 #else
3164 #define _FieldUpgradeStartDataAddress 0
3165 #endif // CC_FieldUpgradeStart
3166 #if CC_FieldUpgradeData
3167 #include "FieldUpgradeData_fp.h"
3168 typedef TPM_RC (FieldUpgradeData_Entry)(
3169 FieldUpgradeData_In *in,
3170 FieldUpgradeData_Out *out
3171 );
3172 typedef const struct {
3173 FieldUpgradeData_Entry *entry;
3174 UINT16 inSize;
3175 UINT16 outSize;
3176 UINT16 offsetOfTypes;
3177 UINT16 paramOffsets[1];
3178 BYTE types[5];
3179 } FieldUpgradeData_COMMAND_DESCRIPTOR_t;
3180 FieldUpgradeData_COMMAND_DESCRIPTOR_t _FieldUpgradeDataData = {
3181 /* entry */ &TPM2_FieldUpgradeData,
3182 /* inSize */ (UINT16)(sizeof(FieldUpgradeData_In)),
3183 /* outSize */ (UINT16)(sizeof(FieldUpgradeData_Out)),
3184 /* offsetOfTypes */ offsetof(FieldUpgradeData_COMMAND_DESCRIPTOR_t, types),
3185 /* offsets */ {(UINT16)(offsetof(FieldUpgradeData_Out, firstDigest))},
3186 /* types */ {TPM2B_MAX_BUFFER_P_UNMARSHAL,
3187 END_OF_LIST,
3188 TPMT_HA_P_MARSHAL,
3189 TPMT_HA_P_MARSHAL,
3190 END_OF_LIST}
3191 };
3192 #define _FieldUpgradeDataDataAddress (&_FieldUpgradeDataData)
3193 #else
3194 #define _FieldUpgradeDataDataAddress 0
3195 #endif // CC_FieldUpgradeData
3196 #if CC_FirmwareRead
3197 #include "FirmwareRead_fp.h"
3198 typedef TPM_RC (FirmwareRead_Entry)(
3199 FirmwareRead_In *in,
3200 FirmwareRead_Out *out
3201 );
3202 typedef const struct {
3203 FirmwareRead_Entry *entry;
3204 UINT16 inSize;
3205 UINT16 outSize;
3206 UINT16 offsetOfTypes;
3207 BYTE types[4];
3208 } FirmwareRead_COMMAND_DESCRIPTOR_t;
3209 FirmwareRead_COMMAND_DESCRIPTOR_t _FirmwareReadData = {
3210 /* entry */ &TPM2_FirmwareRead,
3211 /* inSize */ (UINT16)(sizeof(FirmwareRead_In)),
3212 /* outSize */ (UINT16)(sizeof(FirmwareRead_Out)),
3213 /* offsetOfTypes */ offsetof(FirmwareRead_COMMAND_DESCRIPTOR_t, types),
3214 /* offsets */ // No parameter offsets;
3215 /* types */ {UINT32_P_UNMARSHAL,
3216 END_OF_LIST,
3217 TPM2B_MAX_BUFFER_P_MARSHAL,
3218 END_OF_LIST}
3219 };
3220 #define _FirmwareReadDataAddress (&_FirmwareReadData)
3221 #else
3222 #define _FirmwareReadDataAddress 0
3223 #endif // CC_FirmwareRead
3224 #if CC_ContextSave
3225 #include "ContextSave_fp.h"
3490 } NV_DefineSpace_COMMAND_DESCRIPTOR_t;
3491 NV_DefineSpace_COMMAND_DESCRIPTOR_t _NV_DefineSpaceData = {
3492 /* entry */ &TPM2_NV_DefineSpace,
3493 /* inSize */ (UINT16)(sizeof(NV_DefineSpace_In)),
3494 /* outSize */ 0,
3495 /* offsetOfTypes */ offsetof(NV_DefineSpace_COMMAND_DESCRIPTOR_t, types),
3496 /* offsets */ {(UINT16)(offsetof(NV_DefineSpace_In, auth)),
3497 (UINT16)(offsetof(NV_DefineSpace_In, publicInfo))},
3498 /* types */ {TPMI_RH_PROVISION_H_UNMARSHAL,
3499 TPM2B_AUTH_P_UNMARSHAL,
3500 TPM2B_NV_PUBLIC_P_UNMARSHAL,
3501 END_OF_LIST,
3502 END_OF_LIST}
3503 };
3504 #define _NV_DefineSpaceDataAddress (&_NV_DefineSpaceData)
3505 #else
3506 #define _NV_DefineSpaceDataAddress 0
3507 #endif // CC_NV_DefineSpace
3508 #if CC_NV_UndefineSpace
3509 #include "NV_UndefineSpace_fp.h"
3510 typedef TPM_RC (NV_UndefineSpace_Entry)(
3511 NV_UndefineSpace_In *in
3512 );
3513 typedef const struct {
3514 NV_UndefineSpace_Entry *entry;
3515 UINT16 inSize;
3516 UINT16 outSize;
3517 UINT16 offsetOfTypes;
3518 UINT16 paramOffsets[1];
3519 BYTE types[4];
3520 } NV_UndefineSpace_COMMAND_DESCRIPTOR_t;
3521 NV_UndefineSpace_COMMAND_DESCRIPTOR_t _NV_UndefineSpaceData = {
3522 /* entry */ &TPM2_NV_UndefineSpace,
3523 /* inSize */ (UINT16)(sizeof(NV_UndefineSpace_In)),
3524 /* outSize */ 0,
3525 /* offsetOfTypes */ offsetof(NV_UndefineSpace_COMMAND_DESCRIPTOR_t, types),
3526 /* offsets */ {(UINT16)(offsetof(NV_UndefineSpace_In, nvIndex))},
3527 /* types */ {TPMI_RH_PROVISION_H_UNMARSHAL,
3528 TPMI_RH_NV_INDEX_H_UNMARSHAL,
3529 END_OF_LIST,
3530 END_OF_LIST}
3531 };
3532 #define _NV_UndefineSpaceDataAddress (&_NV_UndefineSpaceData)
3533 #else
3534 #define _NV_UndefineSpaceDataAddress 0
3535 #endif // CC_NV_UndefineSpace
3536 #if CC_NV_UndefineSpaceSpecial
3537 #include "NV_UndefineSpaceSpecial_fp.h"
3538 typedef TPM_RC (NV_UndefineSpaceSpecial_Entry)(
3539 NV_UndefineSpaceSpecial_In *in
3540 );
3541 typedef const struct {
3542 NV_UndefineSpaceSpecial_Entry *entry;
3543 UINT16 inSize;
3544 UINT16 outSize;
3545 UINT16 offsetOfTypes;
3546 UINT16 paramOffsets[1];
3547 BYTE types[4];
3548 } NV_UndefineSpaceSpecial_COMMAND_DESCRIPTOR_t;
3549 NV_UndefineSpaceSpecial_COMMAND_DESCRIPTOR_t _NV_UndefineSpaceSpecialData = {
3550 /* entry */ &TPM2_NV_UndefineSpaceSpecial,
3551 /* inSize */ (UINT16)(sizeof(NV_UndefineSpaceSpecial_In)),
3552 /* outSize */ 0,
3553 /* offsetOfTypes */
offsetof(NV_UndefineSpaceSpecial_COMMAND_DESCRIPTOR_t, types),
3619 END_OF_LIST,
3620 END_OF_LIST}
3621 };
3622 #define _NV_WriteDataAddress (&_NV_WriteData)
3623 #else
3624 #define _NV_WriteDataAddress 0
3625 #endif // CC_NV_Write
3626 #if CC_NV_Increment
3627 #include "NV_Increment_fp.h"
3628 typedef TPM_RC (NV_Increment_Entry)(
3629 NV_Increment_In *in
3630 );
3631 typedef const struct {
3632 NV_Increment_Entry *entry;
3633 UINT16 inSize;
3634 UINT16 outSize;
3635 UINT16 offsetOfTypes;
3636 UINT16 paramOffsets[1];
3637 BYTE types[4];
3638 } NV_Increment_COMMAND_DESCRIPTOR_t;
3639 NV_Increment_COMMAND_DESCRIPTOR_t _NV_IncrementData = {
3640 /* entry */ &TPM2_NV_Increment,
3641 /* inSize */ (UINT16)(sizeof(NV_Increment_In)),
3642 /* outSize */ 0,
3643 /* offsetOfTypes */ offsetof(NV_Increment_COMMAND_DESCRIPTOR_t, types),
3644 /* offsets */ {(UINT16)(offsetof(NV_Increment_In, nvIndex))},
3645 /* types */ {TPMI_RH_NV_AUTH_H_UNMARSHAL,
3646 TPMI_RH_NV_INDEX_H_UNMARSHAL,
3647 END_OF_LIST,
3648 END_OF_LIST}
3649 };
3650 #define _NV_IncrementDataAddress (&_NV_IncrementData)
3651 #else
3652 #define _NV_IncrementDataAddress 0
3653 #endif // CC_NV_Increment
3654 #if CC_NV_Extend
3655 #include "NV_Extend_fp.h"
3656 typedef TPM_RC (NV_Extend_Entry)(
3657 NV_Extend_In *in
3658 );
3659 typedef const struct {
3660 NV_Extend_Entry *entry;
3661 UINT16 inSize;
3662 UINT16 outSize;
3663 UINT16 offsetOfTypes;
3664 UINT16 paramOffsets[2];
3665 BYTE types[5];
3666 } NV_Extend_COMMAND_DESCRIPTOR_t;
3667 NV_Extend_COMMAND_DESCRIPTOR_t _NV_ExtendData = {
3668 /* entry */ &TPM2_NV_Extend,
3669 /* inSize */ (UINT16)(sizeof(NV_Extend_In)),
3670 /* outSize */ 0,
3671 /* offsetOfTypes */ offsetof(NV_Extend_COMMAND_DESCRIPTOR_t, types),
3672 /* offsets */ {(UINT16)(offsetof(NV_Extend_In, nvIndex)),
3673 (UINT16)(offsetof(NV_Extend_In, data))},
3674 /* types */ {TPMI_RH_NV_AUTH_H_UNMARSHAL,
3675 TPMI_RH_NV_INDEX_H_UNMARSHAL,
3676 TPM2B_MAX_NV_BUFFER_P_UNMARSHAL,
3677 END_OF_LIST,
3678 END_OF_LIST}
3679 };
3680 #define _NV_ExtendDataAddress (&_NV_ExtendData)
3681 #else
3682 #define _NV_ExtendDataAddress 0
3683 #endif // CC_NV_Extend
3684 #if CC_NV_SetBits
3947 } AC_Send_COMMAND_DESCRIPTOR_t;
3948 AC_Send_COMMAND_DESCRIPTOR_t _AC_SendData = {
3949 /* entry */ &TPM2_AC_Send,
3950 /* inSize */ (UINT16)(sizeof(AC_Send_In)),
3951 /* outSize */ (UINT16)(sizeof(AC_Send_Out)),
3952 /* offsetOfTypes */ offsetof(AC_Send_COMMAND_DESCRIPTOR_t, types),
3953 /* offsets */ {(UINT16)(offsetof(AC_Send_In, authHandle)),
3954 (UINT16)(offsetof(AC_Send_In, ac)),
3955 (UINT16)(offsetof(AC_Send_In, acDataIn))},
3956 /* types */ {TPMI_DH_OBJECT_H_UNMARSHAL,
3957 TPMI_RH_NV_AUTH_H_UNMARSHAL,
3958 TPMI_RH_AC_H_UNMARSHAL,
3959 TPM2B_MAX_BUFFER_P_UNMARSHAL,
3960 END_OF_LIST,
3961 TPMS_AC_OUTPUT_P_MARSHAL,
3962 END_OF_LIST}
3963 };
3964 #define _AC_SendDataAddress (&_AC_SendData)
3965 #else
3966 #define _AC_SendDataAddress 0
3967 #endif // CC_AC_Send
3968 #if CC_Policy_AC_SendSelect
3969 #include "Policy_AC_SendSelect_fp.h"
3970 typedef TPM_RC (Policy_AC_SendSelect_Entry)(
3971 Policy_AC_SendSelect_In *in
3972 );
3973 typedef const struct {
3974 Policy_AC_SendSelect_Entry *entry;
3975 UINT16 inSize;
3976 UINT16 outSize;
3977 UINT16 offsetOfTypes;
3978 UINT16 paramOffsets[4];
3979 BYTE types[7];
3980 } Policy_AC_SendSelect_COMMAND_DESCRIPTOR_t;
3981 Policy_AC_SendSelect_COMMAND_DESCRIPTOR_t _Policy_AC_SendSelectData = {
3982 /* entry */ &TPM2_Policy_AC_SendSelect,
3983 /* inSize */ (UINT16)(sizeof(Policy_AC_SendSelect_In)),
3984 /* outSize */ 0,
3985 /* offsetOfTypes */ offsetof(Policy_AC_SendSelect_COMMAND_DESCRIPTOR_t,
types),
3986 /* offsets */ {(UINT16)(offsetof(Policy_AC_SendSelect_In,
objectName)),
3987 (UINT16)(offsetof(Policy_AC_SendSelect_In,
authHandleName)),
3988 (UINT16)(offsetof(Policy_AC_SendSelect_In, acName)),
3989 (UINT16)(offsetof(Policy_AC_SendSelect_In,
includeObject))},
3990 /* types */ {TPMI_SH_POLICY_H_UNMARSHAL,
3991 TPM2B_NAME_P_UNMARSHAL,
3992 TPM2B_NAME_P_UNMARSHAL,
3993 TPM2B_NAME_P_UNMARSHAL,
3994 TPMI_YES_NO_P_UNMARSHAL,
3995 END_OF_LIST,
3996 END_OF_LIST}
3997 };
3998 #define _Policy_AC_SendSelectDataAddress (&_Policy_AC_SendSelectData)
3999 #else
4000 #define _Policy_AC_SendSelectDataAddress 0
4001 #endif // CC_Policy_AC_SendSelect
4002 #if CC_ACT_SetTimeout
4003 #include "ACT_SetTimeout_fp.h"
4004 typedef TPM_RC (ACT_SetTimeout_Entry)(
4005 ACT_SetTimeout_In *in
4006 );
4007 typedef const struct {
4008 ACT_SetTimeout_Entry *entry;
5.7 Commands.h
1 #ifndef _COMMANDS_H_
2 #define _COMMANDS_H_
Start-up
3 #ifdef TPM_CC_Startup
4 #include "Startup_fp.h"
5 #endif
6 #ifdef TPM_CC_Shutdown
7 #include "Shutdown_fp.h"
8 #endif
Testing
9 #ifdef TPM_CC_SelfTest
10 #include "SelfTest_fp.h"
11 #endif
12 #ifdef TPM_CC_IncrementalSelfTest
13 #include "IncrementalSelfTest_fp.h"
14 #endif
15 #ifdef TPM_CC_GetTestResult
16 #include "GetTestResult_fp.h"
17 #endif
Session Commands
18 #ifdef TPM_CC_StartAuthSession
19 #include "StartAuthSession_fp.h"
20 #endif
21 #ifdef TPM_CC_PolicyRestart
22 #include "PolicyRestart_fp.h"
23 #endif
Object Commands
24 #ifdef TPM_CC_Create
25 #include "Create_fp.h"
26 #endif
27 #ifdef TPM_CC_Load
28 #include "Load_fp.h"
29 #endif
30 #ifdef TPM_CC_LoadExternal
31 #include "LoadExternal_fp.h"
32 #endif
33 #ifdef TPM_CC_ReadPublic
34 #include "ReadPublic_fp.h"
35 #endif
36 #ifdef TPM_CC_ActivateCredential
37 #include "ActivateCredential_fp.h"
38 #endif
39 #ifdef TPM_CC_MakeCredential
40 #include "MakeCredential_fp.h"
41 #endif
42 #ifdef TPM_CC_Unseal
43 #include "Unseal_fp.h"
44 #endif
45 #ifdef TPM_CC_ObjectChangeAuth
46 #include "ObjectChangeAuth_fp.h"
47 #endif
48 #ifdef TPM_CC_CreateLoaded
49 #include "CreateLoaded_fp.h"
50 #endif
Duplication Commands
51 #ifdef TPM_CC_Duplicate
52 #include "Duplicate_fp.h"
53 #endif
54 #ifdef TPM_CC_Rewrap
55 #include "Rewrap_fp.h"
56 #endif
57 #ifdef TPM_CC_Import
58 #include "Import_fp.h"
59 #endif
Asymmetric Primitives
60 #ifdef TPM_CC_RSA_Encrypt
61 #include "RSA_Encrypt_fp.h"
62 #endif
63 #ifdef TPM_CC_RSA_Decrypt
64 #include "RSA_Decrypt_fp.h"
65 #endif
66 #ifdef TPM_CC_ECDH_KeyGen
67 #include "ECDH_KeyGen_fp.h"
68 #endif
69 #ifdef TPM_CC_ECDH_ZGen
70 #include "ECDH_ZGen_fp.h"
71 #endif
72 #ifdef TPM_CC_ECC_Parameters
73 #include "ECC_Parameters_fp.h"
74 #endif
75 #ifdef TPM_CC_ZGen_2Phase
76 #include "ZGen_2Phase_fp.h"
77 #endif
Symmetric Primitives
78 #ifdef TPM_CC_EncryptDecrypt
79 #include "EncryptDecrypt_fp.h"
80 #endif
81 #ifdef TPM_CC_EncryptDecrypt2
82 #include "EncryptDecrypt2_fp.h"
83 #endif
84 #ifdef TPM_CC_Hash
85 #include "Hash_fp.h"
86 #endif
87 #ifdef TPM_CC_HMAC
88 #include "HMAC_fp.h"
89 #endif
90 #ifdef TPM_CC_MAC
91 #include "MAC_fp.h"
92 #endif
93 #ifdef TPM_CC_GetRandom
94 #include "GetRandom_fp.h"
95 #endif
96 #ifdef TPM_CC_StirRandom
97 #include "StirRandom_fp.h"
98 #endif
Hash/HMAC/Event Sequences
99 #ifdef TPM_CC_HMAC_Start
100 #include "HMAC_Start_fp.h"
101 #endif
102 #ifdef TPM_CC_MAC_Start
103 #include "MAC_Start_fp.h"
104 #endif
105 #ifdef TPM_CC_HashSequenceStart
106 #include "HashSequenceStart_fp.h"
107 #endif
108 #ifdef TPM_CC_SequenceUpdate
109 #include "SequenceUpdate_fp.h"
110 #endif
111 #ifdef TPM_CC_SequenceComplete
112 #include "SequenceComplete_fp.h"
113 #endif
114 #ifdef TPM_CC_EventSequenceComplete
115 #include "EventSequenceComplete_fp.h"
116 #endif
Attestation Commands
Ephemeral EC Keys
Command Audit
Hierarchy Commands
Field Upgrade
Context Management
Capability Commands
Non-volatile Storage
Attached Components
Vendor Specific
5.8 CompilerDependencies.h
This file contains the build switches. This contains switches for multiple versions of the crypto-library so
some may not apply to your environment.
1 #ifndef _COMPILER_DEPENDENCIES_H_
2 #define _COMPILER_DEPENDENCIES_H_
3 #ifdef GCC
4 # undef _MSC_VER
5 # undef WIN32
6 #endif
7 #ifdef _MSC_VER
These definitions are for the Microsoft compiler Endian conversion for aligned structures
11 //#define _NO_CRT_STDIO_INLINE
This macro is used to handle LIB_EXPORT of function and variable names in lieu of a .def file. Visual
Studio requires that functions be explicitly exported and imported.
This is defined to indicate a function that does not return. Microsoft compilers do not support the
_Noretrun function parameter.
Lower the compiler error warning for system include files. They tend not to be that clean and there is no
reason to sort through all the spurious errors that they generate when the normal error level is set to /Wall
24 # define _REDUCE_WARNING_LEVEL_(n) \
25 __pragma(warning(push, n))
26 # define _NORMAL_WARNING_LEVEL_ \
27 __pragma(warning(pop))
28 # include <stdint.h>
29 #endif
30 #ifndef _MSC_VER
31 #ifndef WINAPI
32 # define WINAPI
33 #endif
34 # define __pragma(x)
35 # define REVERSE_ENDIAN_16(_Number) __builtin_bswap16(_Number)
43 #ifndef NORETURN
44 # define NORETURN
45 #endif
46 #ifndef LIB_EXPORT
47 # define LIB_EXPORT
48 #endif
49 #ifndef LIB_IMPORT
50 # define LIB_IMPORT
51 #endif
52 #ifndef _REDUCE_WARNING_LEVEL_
53 # define _REDUCE_WARNING_LEVEL_(n)
54 #endif
55 #ifndef _NORMAL_WARNING_LEVEL_
56 # define _NORMAL_WARNING_LEVEL_
57 #endif
58 #ifndef NOT_REFERENCED
59 # define NOT_REFERENCED(x) (x = x)
60 #endif
61 #ifdef _POSIX_
62 typedef int SOCKET;
63 #endif
64 #endif // _COMPILER_DEPENDENCIES_H_
5.9 Global.h
5.9.1 Description
This file contains internal global type definitions and data declarations that are need between
subsystems. The instantiation of global data is in Global.c. The initialization of global data is in the
subsystem that is the primary owner of the data.
The first part of this file has the typedefs for structures and other defines used in many portions of the
code. After the typedef section, is a section that defines global values that are only present in RAM. The
next three sections define the structures for the NV data areas: persistent, orderly, and state save.
Additional sections define the data that is used in specific modules. That data is private to the module but
is collected here to simplify the management of the instance data. All the data is instanced in Global.c.
5.9.2 Includes
4 #ifndef GLOBAL_H
5 #define GLOBAL_H
6 _REDUCE_WARNING_LEVEL_(2)
7 #include <string.h>
8 #include <stddef.h>
9 _NORMAL_WARNING_LEVEL_
10
11 #include "Capabilities.h"
12 #include "TpmTypes.h"
13 #include "CommandAttributes.h"
14 #include "CryptTest.h"
15 #include "BnValues.h"
16 #include "CryptHash.h"
17 #include "CryptSym.h"
18 #include "CryptRand.h"
19 #include "CryptEcc.h"
20 #include "CryptRsa.h"
21 #include "CryptTest.h"
22 #include "TpmError.h"
23 #include "NV.h"
24 #include "ACT.h"
25
26 //** Defines and Types
27
28 //*** Size Types
29 // These types are used to differentiate the two different size values used.
30 //
31 // NUMBYTES is used when a size is a number of bytes (usually a TPM2B)
32 typedef UINT16 NUMBYTES;
33
34 //*** Other Types
35 // An AUTH_VALUE is a BYTE array containing a digest (TPMU_HA)
36 typedef BYTE AUTH_VALUE[sizeof(TPMU_HA)];
39 TPM2B_TYPE(PROOF, PROOF_SIZE);
40 TPM2B_TYPE(SEED, PRIMARY_SEED_SIZE);
A CLOCK_NONCE is used to tag the time value in the authorization session and in the ticket computation
so that the ticket expires when there is a time discontinuity. When the clock stops during normal
operation, the nonce is 64-bit value kept in RAM but it is a 32-bit counter when the clock only stops during
power events.
41 #if CLOCK_STOPS
42 typedef UINT64 CLOCK_NONCE;
43 #else
44 typedef UINT32 CLOCK_NONCE;
45 #endif
5.9.3.1 Description
The structures in this section define the object layout as it exists in TPM memory.
Two types of objects are defined: an ordinary object such as a key, and a sequence object that may be a
hash, HMAC, or event.
5.9.3.2 OBJECT_ATTRIBUTES
An OBJECT_ATTRIBUTES structure contains the variable attributes of an object. These properties are
not part of the public properties but are used by the TPM in managing the object. An
OBJECT_ATTRIBUTES is used in the definition of the OBJECT data type.
46 typedef struct
47 {
48 unsigned publicOnly : 1; //0) SET if only the public portion of
49 // an object is loaded
50 unsigned epsHierarchy : 1; //1) SET if the object belongs to EPS
51 // Hierarchy
52 unsigned ppsHierarchy : 1; //2) SET if the object belongs to PPS
53 // Hierarchy
54 unsigned spsHierarchy : 1; //3) SET f the object belongs to SPS
55 // Hierarchy
56 unsigned evict : 1; //4) SET if the object is a platform or
57 // owner evict object. Platform-
58 // evict object belongs to PPS
59 // hierarchy, owner-evict object
60 // belongs to SPS or EPS hierarchy.
61 // This bit is also used to mark a
62 // completed sequence object so it
63 // will be flush when the
64 // SequenceComplete command succeeds.
65 unsigned primary : 1; //5) SET for a primary object
66 unsigned temporary : 1; //6) SET for a temporary object
67 unsigned stClear : 1; //7) SET for an stClear object
68 unsigned hmacSeq : 1; //8) SET for an HMAC or MAC sequence
69 // object
70 unsigned hashSeq : 1; //9) SET for a hash sequence object
71 unsigned eventSeq : 1; //10) SET for an event sequence object
There is an overload of the sensitive.rsa.t.size field of a TPMT_SENSITIVE when an RSA key is loaded.
When the sensitive->sensitive contains an RSA key with all of the CRT values, then the MSB of the size
field will be set to indicate that the buffer contains all 5 of the CRT private key values.
An OBJECT structure holds the object public, sensitive, and meta-data associated. This structure is
implementation dependent. For this implementation, the structure is not optimized for space but rather for
clarity of the reference implementation. Other implementations may choose to overlap portions of the
structure that are not used simultaneously. These changes would necessitate changes to the source code
but those changes would be compatible with the reference implementation.
107 {
108 OBJECT_ATTRIBUTES attributes; // The attributes of the HASH object
109 TPMI_ALG_PUBLIC type; // algorithm
110 TPMI_ALG_HASH nameAlg; // name algorithm
111 TPMA_OBJECT objectAttributes; // object attributes
112
113 // The data below is unique to a sequence object
114 TPM2B_AUTH auth; // authorization for use of sequence
115 union
116 {
117 HASH_STATE hashState[HASH_COUNT];
118 HMAC_STATE hmacState;
119 } state;
120 } HASH_OBJECT;
121 typedef BYTE HASH_OBJECT_BUFFER[sizeof(HASH_OBJECT)];
5.9.3.5 ANY_OBJECT
This is the union for holding either a sequence object or a regular object. for ContextSave() and
ContextLoad()
5.9.5.1 Description
The structures in this section define the internal structure of a session context.
5.9.5.2 SESSION_ATTRIBUTES
The attributes in the SESSION_ATTRIBUTES structure track the various properties of the session. It
maintains most of the tracking state information for the policy session. It is used within the SESSION
structure.
The SESSION structure contains all the context of a session except for the associated contextID.
NOTE: The contextID of a session is only relevant when the session context is stored off the TPM.
5.9.6 PCR
The PCR_SAVE structure type contains the PCR data that are saved across power cycles. Only the static
PCR are required to be saved across power cycles. The DRTM and resettable PCR are not saved. The
number of static and resettable PCR is determined by the platform-specific specification to which the TPM
is built.
252 // to increment.
253 UINT32 pcrCounter;
254 } PCR_SAVE;
5.9.6.2 PCR_POLICY
This structure holds the PCR policies, one for each group of PCR controlled by policy.
5.9.6.3 PCR_AUTHVALUE
This structure holds the PCR policies, one for each group of PCR controlled by policy.
5.9.7 STARTUP_TYPE
This enumeration is the possible startup types. The type is determined by the combination of
TPM2_ShutDown() and TPM2_Startup().
5.9.8 NV
5.9.8.1 NV_INDEX
The NV_INDEX structure defines the internal format for an NV index. The indexData size varies
according to the type of the index. In this implementation, all of the index is manipulated as a unit.
5.9.8.2 NV_REF
An NV_REF is an opaque value returned by the NV subsystem. It is used to reference and NV Index in a
relatively efficient way. Rather than having to continually search for an Index, its reference value may be
used. In this implementation, an NV_REF is a byte pointer that points to the copy of the NV memory that
is kept in RAM.
5.9.8.3 NV_PIN
This structure deals with the possible endianess differences between the canonical form of the
TPMS_NV_PIN_COUNTER_PARAMETERS structure and the internal value. The structures allow the
data in a PIN index to be read as an 8-octet value using NvReadUINT64Data(). That function will byte
swap all the values on a little endian system. This will put the bytes with the 4-octet values in the correct
order but will swap the pinLimit and pinCount values. When written, the PIN index is simply handled as a
normal index with the octets in canonical order.
5.9.9 COMMIT_INDEX_MASK
This is the define for the mask value that is used when manipulating the bits in the commit bit array. The
commit counter is a 64-bit value and the low order bits are used to index the commitArray. This mask
value is applied to the commit counter to extract the bit number in the array.
5.9.10.1 Description
The values in this section are only extant in RAM or ROM as constant values.
307 // This is an implementation choice and the same result can be achieved by using
308 // a macro.
309 #define g_rcIndexInitializer { TPM_RC_1, TPM_RC_2, TPM_RC_3, TPM_RC_4, \
310 TPM_RC_5, TPM_RC_6, TPM_RC_7, TPM_RC_8,
\
311 TPM_RC_9, TPM_RC_A, TPM_RC_B, TPM_RC_C,
\
312 TPM_RC_D, TPM_RC_E, TPM_RC_F }
313 EXTERN const UINT16 g_rcIndex[15] INITIALIZER(g_rcIndexInitializer);
5.9.10.3 g_exclusiveAuditSession
This location holds the session handle for the current exclusive audit session. If there is no exclusive
audit session, the location is set to TPM_RH_UNASSIGNED.
5.9.10.4 TPM_SU_DA_USED
As with TPM_SU_NONE, this value is added to allow indication that the shutdown was not orderly and
that a DA=protected object was reference during the previous cycle.
These flags are included in gp.orderlyState. These are hacks and are being used to avoid having to
change the layout of gp. The PRE_STARTUP_FLAG indicates that a _TPM_Hash_Start()/_Data/_End
sequence was received after _TPM_Init() but before TPM2_StartUp(). STARTUP_LOCALITY_3 indicates
that the last TPM2_Startup() was received at locality 3. These flags are only relevant if after a
TPM2_Shutdown(STATE).
5.9.10.6 g_daUsed
This location indicates if a DA-protected value is accessed during a boot cycle. If none has, then there is
no need to increment failedTries on the next non-orderly startup. This bit is merged with gp.orderlyState
when that gp.orderly is set to SU_NONE_VALUE
401 // Note: When power is applied, this value can come up as anything. However,
402 // _plat__WasPowerLost() will provide the proper indication in that case. So, when
403 // power is actually lost, we get the correct answer. When power was not lost, but
404 // the power-lost processing has not been completed before the next _TPM_Init(),
405 // then the TPM still does the correct thing.
406 EXTERN BOOL g_powerWasLost;
407
408 //*** g_clearOrderly
409 // This flag indicates if the execution of a command should cause the orderly
410 // state to be cleared. This flag is set to FALSE at the beginning of each
411 // command in ExecuteCommand() and is checked in ExecuteCommand() after the
412 // detailed actions of a command complete but before the check of
413 // 'g_updateNV'. If this flag is TRUE, and the orderly state is not
414 // SU_NONE_VALUE, then the orderly state in NV memory will be changed to
415 // SU_NONE_VALUE or SU_DA_USED_VALUE.
416 EXTERN BOOL g_clearOrderly;
417
418 //*** g_prevOrderlyState
419 // This location indicates how the TPM was shut down before the most recent
420 // TPM2_Startup(). This value, along with the startup type, determines if
421 // the TPM should do a TPM Reset, TPM Restart, or TPM Resume.
422 EXTERN TPM_SU g_prevOrderlyState;
423
424 //*** g_nvOk
425 // This value indicates if the NV integrity check was successful or not. If not and
426 // the failure was severe, then the TPM would have been put into failure mode after
427 // it had been re-manufactured. If the NV failure was in the area where the state-save
428 // data is kept, then this variable will have a value of FALSE indicating that
429 // a TPM2_Startup(CLEAR) is required.
430 EXTERN BOOL g_nvOk;
431 // NV availability is sampled as the start of each command and stored here
432 // so that its value remains consistent during the command execution
433 EXTERN TPM_RC g_NvStatus;
434
435 //*** g_platformUnique
436 // This location contains the unique value(s) used to identify the TPM. It is
437 // loaded on every _TPM2_Startup()
438 // The first value is used to seed the RNG. The second value is used as a vendor
439 // authValue. The value used by the RNG would be the value derived from the
440 // chip unique value (such as fused) with a dependency on the authorities of the
441 // code in the TPM boot path. The second would be derived from the chip unique value
442 // with a dependency on the details of the code in the boot path. That is, the
443 // first value depends on the various signers of the code and the second depends on
444 // what was signed. The TPM vendor should not be able to know the first value but
445 // they are expected to know the second.
446 EXTERN TPM2B_AUTH g_platformUniqueAuthorities; // Reserved for RNG
447
448 EXTERN TPM2B_AUTH g_platformUniqueDetails; // referenced by
VENDOR_PERMANENT
449
450 //*********************************************************************************
451 //*********************************************************************************
452 //** Persistent Global Values
453 //*********************************************************************************
454 //*********************************************************************************
455 //*** Description
456 // The values in this section are global values that are persistent across power
457 // events. The lifetime of the values determines the structure in which the value
458 // is placed.
459
460 //*********************************************************************************
461 //*** PERSISTENT_DATA
462 //*********************************************************************************
463 // This structure holds the persistent values that only change as a consequence
464 // of a specific Protected Capability and are not affected by TPM power events
530
531 //*********************************************************************************
532 // Physical Presence
533 //*********************************************************************************
534 // The PP_LIST type contains a bit map of the commands that require physical
535 // to be asserted when the authorization is evaluated. Physical presence will be
536 // checked if the corresponding bit in the array is SET and if the authorization
537 // handle is TPM_RH_PLATFORM.
538 //
539 // These bits may be changed with TPM2_PP_Commands().
540 BYTE ppList[(COMMAND_COUNT + 7) / 8];
541
542 //*********************************************************************************
543 // Dictionary attack values
544 //*********************************************************************************
545 // These values are used for dictionary attack tracking and control.
546 UINT32 failedTries; // the current count of unexpired
547 // authorization failures
548
549 UINT32 maxTries; // number of unexpired authorization
550 // failures before the TPM is in
551 // lockout
552
553 UINT32 recoveryTime; // time between authorization failures
554 // before failedTries is decremented
555
556 UINT32 lockoutRecovery; // time that must expire between
557 // authorization failures associated
558 // with lockoutAuth
559
560 BOOL lockOutAuthEnabled; // TRUE if use of lockoutAuth is
561 // allowed
562
563 //*****************************************************************************
564 // Orderly State
565 //*****************************************************************************
566 // The orderly state for current cycle
567 TPM_SU orderlyState;
568
569 //*****************************************************************************
570 // Command audit values.
571 //*****************************************************************************
572 BYTE auditCommands[((COMMAND_COUNT + 1) + 7) / 8];
573 TPMI_ALG_HASH auditHashAlg;
574 UINT64 auditCounter;
575
576 //*****************************************************************************
577 // Algorithm selection
578 //*****************************************************************************
579 //
580 // The 'algorithmSet' value indicates the collection of algorithms that are
581 // currently in used on the TPM. The interpretation of value is vendor dependent.
582 UINT32 algorithmSet;
583
584 //*****************************************************************************
585 // Firmware version
586 //*****************************************************************************
587 // The firmwareV1 and firmwareV2 values are instanced in TimeStamp.c. This is
588 // a scheme used in development to allow determination of the linker build time
589 // of the TPM. An actual implementation would implement these values in a way that
590 // is consistent with vendor needs. The values are maintained in RAM for simplified
591 // access with a master version in NV. These values are modified in a
592 // vendor-specific way.
593
594 // g_firmwareV1 contains the more significant 32-bits of the vendor version number.
595 // In the reference implementation, if this value is printed as a hex
661 // structure.
662 UINT32 signaledACT;
663 } ORDERLY_DATA;
664 #if ACCUMULATE_SELF_HEAL_TIMER
665 #define s_selfHealTimer go.selfHealTimer
666 #define s_lockoutTimer go.lockoutTimer
667 #endif // ACCUMULATE_SELF_HEAL_TIMER
668 # define drbgDefault go.drbgState
669 EXTERN ORDERLY_DATA go;
670
671 //*********************************************************************************
672 //*********************************************************************************
673 //*** STATE_CLEAR_DATA
674 //*********************************************************************************
675 //*********************************************************************************
676 // This structure contains the data that is saved on Shutdown(STATE)
677 // and restored on Startup(STATE). The values are set to their default
678 // settings on any Startup(Clear). In other words, the data is only persistent
679 // across TPM Resume.
680 //
681 // If the comments associated with a parameter indicate a default reset value, the
682 // value is applied on each Startup(CLEAR).
683
684 typedef struct state_clear_data
685 {
686 //*****************************************************************************
687 // Hierarchy Control
688 //*****************************************************************************
689 BOOL shEnable; // default reset is SET
690 BOOL ehEnable; // default reset is SET
691 BOOL phEnableNV; // default reset is SET
692 TPMI_ALG_HASH platformAlg; // default reset is TPM_ALG_NULL
693 TPM2B_DIGEST platformPolicy; // default reset is an Empty Buffer
694 TPM2B_AUTH platformAuth; // default reset is an Empty Buffer
695
696 //*****************************************************************************
697 // PCR
698 //*****************************************************************************
699 // The set of PCR to be saved on Shutdown(STATE)
700 PCR_SAVE pcrSave; // default reset is 0...0
701
702 // This structure hold the authorization values for those PCR that have an
703 // update authorization.
704 // This implementation only supports a single group of PCR controlled by
705 // authorization. If more are required, then this structure would be changed to
706 // an array.
707 PCR_AUTHVALUE pcrAuthValues;
708
709 //*****************************************************************************
710 // ACT
711 //*****************************************************************************
712 #define DefineActPolicySpace(N) TPMT_HA act_##N;
713 FOR_EACH_ACT(DefineActPolicySpace)
714
715 } STATE_CLEAR_DATA;
716 EXTERN STATE_CLEAR_DATA gc;
717
718 //*********************************************************************************
719 //*********************************************************************************
720 //*** State Reset Data
721 //*********************************************************************************
722 //*********************************************************************************
723 // This structure contains data is that is saved on Shutdown(STATE) and restored on
724 // the subsequent Startup(ANY). That is, the data is preserved across TPM Resume
725 // and TPM Restart.
726 //
727 // If a default value is specified in the comments this value is applied on
728 // TPM Reset.
729
730 typedef struct state_reset_data
731 {
732 //*****************************************************************************
733 // Hierarchy Control
734 //*****************************************************************************
735 TPM2B_PROOF nullProof; // The proof value associated with
736 // the TPM_RH_NULL hierarchy. The
737 // default reset value is from the RNG.
738
739 TPM2B_SEED nullSeed; // The seed value for the TPM_RN_NULL
740 // hierarchy. The default reset value
741 // is from the RNG.
742
743 //*****************************************************************************
744 // Context
745 //*****************************************************************************
746 // The 'clearCount' counter is incremented each time the TPM successfully executes
747 // a TPM Resume. The counter is included in each saved context that has 'stClear'
748 // SET (including descendants of keys that have 'stClear' SET). This prevents these
749 // objects from being loaded after a TPM Resume.
750 // If 'clearCount' is at its maximum value when the TPM receives a Shutdown(STATE),
751 // the TPM will return TPM_RC_RANGE and the TPM will only accept Shutdown(CLEAR).
752 UINT32 clearCount; // The default reset value is 0.
753
754 UINT64 objectContextID; // This is the context ID for a saved
755 // object context. The default reset
756 // value is 0.
757 CONTEXT_SLOT contextArray[MAX_ACTIVE_SESSIONS]; // This array
contains
758 // contains the values used to track
759 // the version numbers of saved
760 // contexts (see
761 // Session.c in for details). The
762 // default reset value is {0}.
763
764 CONTEXT_COUNTER contextCounter; // This is the value from which the
765 // 'contextID' is derived. The
766 // default reset value is {0}.
767
768 //*****************************************************************************
769 // Command Audit
770 //*****************************************************************************
771 // When an audited command completes, ExecuteCommand() checks the return
772 // value. If it is TPM_RC_SUCCESS, and the command is an audited command, the
773 // TPM will extend the cpHash and rpHash for the command to this value. If this
774 // digest was the Zero Digest before the cpHash was extended, the audit counter
775 // is incremented.
776
777 TPM2B_DIGEST commandAuditDigest; // This value is set to an Empty Digest
778 // by TPM2_GetCommandAuditDigest() or a
779 // TPM Reset.
780
781 //*****************************************************************************
782 // Boot counter
783 //*****************************************************************************
784
785 UINT32 restartCount; // This counter counts TPM Restarts.
786 // The default reset value is 0.
787
788 //*********************************************************************************
789 // PCR
790 //*********************************************************************************
791 // This counter increments whenever the PCR are updated. This counter is preserved
792 // across TPM Resume even though the PCR are not preserved. This is because
793 // sessions remain active across TPM Restart and the count value in the session
794 // is compared to this counter so this counter must have values that are unique
795 // as long as the sessions are active.
796 // NOTE: A platform-specific specification may designate that certain PCR changes
797 // do not increment this counter to increment.
798 UINT32 pcrCounter; // The default reset value is 0.
799
800 #if ALG_ECC
801
802 //*****************************************************************************
803 // ECDAA
804 //*****************************************************************************
805 UINT64 commitCounter; // This counter increments each time
806 // TPM2_Commit() returns
807 // TPM_RC_SUCCESS. The default reset
808 // value is 0.
809
810 TPM2B_NONCE commitNonce; // This random value is used to compute
811 // the commit values. The default reset
812 // value is from the RNG.
813
814 // This implementation relies on the number of bits in g_commitArray being a
815 // power of 2 (8, 16, 32, 64, etc.) and no greater than 64K.
816 BYTE commitArray[16]; // The default reset value is {0}.
817
818 #endif // ALG_ECC
819 } STATE_RESET_DATA;
820
821 EXTERN STATE_RESET_DATA gr;
822
823 //** NV Layout
824 // The NV data organization is
825 // 1) a PERSISTENT_DATA structure
826 // 2) a STATE_RESET_DATA structure
827 // 3) a STATE_CLEAR_DATA structure
828 // 4) an ORDERLY_DATA structure
829 // 5) the user defined NV index space
830 #define NV_PERSISTENT_DATA (0)
831 #define NV_STATE_RESET_DATA (NV_PERSISTENT_DATA + sizeof(PERSISTENT_DATA))
832 #define NV_STATE_CLEAR_DATA (NV_STATE_RESET_DATA + sizeof(STATE_RESET_DATA))
833 #define NV_ORDERLY_DATA (NV_STATE_CLEAR_DATA + sizeof(STATE_CLEAR_DATA))
834 #define NV_INDEX_RAM_DATA (NV_ORDERLY_DATA + sizeof(ORDERLY_DATA))
835 #define NV_USER_DYNAMIC (NV_INDEX_RAM_DATA + sizeof(s_indexOrderlyRam))
836 #define NV_USER_DYNAMIC_END NV_MEMORY_SIZE
At the start of command processing, the index of the command is determined. This index value is used to
access the various data tables that contain per-command information. There are multiple options for how
the per-command tables can be implemented. This is resolved in GetClosestCommandIndex().
This structure is used to avoid having to manage a large number of parameters being passed through
various levels of the command input processing.
Global sting constants for consistency in KDF function calls. These string constants are shared across
functions to make sure that they are all using consistent sting values.
This structure contains the self-test state values for the cryptographic modules.
This value indicates if a TPM2_Startup() commands has been receive since the power on event. This flag
is maintained in power simulation module because this is the only place that may reliably set this flag to
FALSE.
1011 // allocatable NV space each time an index is deleted or added. This value is
1012 // initialized on Startup. The indices are searched and the maximum of all the
1013 // current counter indices and this value is the initial value for this.
1014 EXTERN UINT64 s_maxCounter;
1015
1016 // This is space used for the NV Index cache. As with a persistent object, the
1017 // contents of a referenced index are copied into the cache so that the
1018 // NV Index memory scanning and data copying can be reduced.
1019 // Only code that operates on NV Index data should use this cache directly. When
1020 // that action code runs, s_lastNvIndex will contain the index header information.
1021 // It will have been loaded when the handles were verified.
1022 // NOTE: An NV index handle can appear in many commands that do not operate on the
1023 // NV data (e.g. TPM2_StartAuthSession). However, only one NV Index at a time is
1024 // ever directly referenced by any command. If that changes, then the NV Index
1025 // caching needs to be changed to accommodate that. Currently, the code will verify
1026 // that only one NV Index is referenced by the handles of the command.
1027 EXTERN NV_INDEX s_cachedNvIndex;
1028 EXTERN NV_REF s_cachedNvRef;
1029 EXTERN BYTE *s_cachedNvRamRef;
1030
1031 // Initial NV Index/evict object iterator value
1032 #define NV_REF_INIT (NV_REF)0xFFFFFFFF
1033 #endif
1068 {
1069 unsigned int stateSave : 1; // if the PCR value should be
1070 // saved in state save
1071 unsigned int resetLocality : 5; // The locality that the PCR
1072 // can be reset
1073 unsigned int extendLocality : 5; // The locality that the PCR
1074 // can be extend
1075 } PCR_Attributes;
1076
1077 EXTERN PCR s_pcrs[IMPLEMENTATION_PCR];
1078
1079 #endif // PCR_C
1080
1081 //*****************************************************************************
1082 //*** From Session.c
1083 //*****************************************************************************
1084 #if defined SESSION_C || defined GLOBAL_C
1085 // Container for HMAC or policy session tracking information
1086 typedef struct
1087 {
1088 BOOL occupied;
1089 SESSION session; // session structure
1090 } SESSION_SLOT;
1091
1092 EXTERN SESSION_SLOT s_sessions[MAX_LOADED_SESSIONS];
1093
1094 // The index in contextArray that has the value of the oldest saved session
1095 // context. When no context is saved, this will have a value that is greater
1096 // than or equal to MAX_ACTIVE_SESSIONS.
1097 EXTERN UINT32 s_oldestSavedSession;
1098
1099 // The number of available session slot openings. When this is 1,
1100 // a session can't be created or loaded if the GAP is maxed out.
1101 // The exception is that the oldest saved session context can always
1102 // be loaded (assuming that there is a space in memory to put it)
1103 EXTERN int s_freeSessionSlots;
1104
1105 #endif // SESSION_C
1106
1107 //*****************************************************************************
1108 //*** From IoBuffers.c
1109 //*****************************************************************************
1110 #if defined IO_BUFFER_C || defined GLOBAL_C
1111 // Each command function is allowed a structure for the inputs to the function and
1112 // a structure for the outputs. The command dispatch code unmarshals the input butter
1113 // to the command action input structure starting at the first byte of
1114 // s_actionIoBuffer. The value of s_actionIoAllocation is the number of UINT64 values
1115 // allocated. It is used to set the pointer for the response structure. The command
1116 // dispatch code will marshal the response values into the final output buffer.
1117 EXTERN UINT64 s_actionIoBuffer[768]; // action I/O buffer
1118 EXTERN UINT32 s_actionIoAllocation; // number of UIN64 allocated for the
1119 // action input structure
1120 #endif // IO_BUFFER_C
1121
1122 //*****************************************************************************
1123 //*** From TPMFail.c
1124 //*****************************************************************************
1125 // This value holds the address of the string containing the name of the function
1126 // in which the failure occurred. This address value isn't useful for anything
1127 // other than helping the vendor to know in which file the failure occurred.
1128 EXTERN BOOL g_inFailureMode; // Indicates that the TPM is in failure mode
1129 #if SIMULATION
1130 EXTERN BOOL g_forceFailureMode; // flag to force failure mode during test
1131 #endif
1132
5.10 GpMacros.h
5.10.1 Introduction
1 #ifndef GP_MACROS_H
2 #define GP_MACROS_H
3 #ifndef NULL
4 #define NULL 0
5 #endif
6 #include "swap.h"
7 #include "VendorString.h"
These macros are used in CryptUtil() to invoke the incremental self test.
8 #if SELF_TEST
9 # define TEST(alg) if(TEST_BIT(alg, g_toTest)) CryptTestAlgorithm(alg, NULL)
Use of TPM_ALG_NULL is reserved for RSAEP/RSADP testing. If someone is wanting to test a hash with
that value, don't do it.
10 # define TEST_HASH(alg) \
11 if(TEST_BIT(alg, g_toTest) \
12 && (alg != ALG_NULL_VALUE)) \
13 CryptTestAlgorithm(alg, NULL)
14 #else
15 # define TEST(alg)
16 # define TEST_HASH(alg)
17 #endif // SELF_TEST
If implementation is using longjmp, then the call to TpmFail() does not return and the compiler will
complain about unreachable code that comes after. To allow for not having longjmp, TpmFail() will return
and the subsequent code will be executed. This macro accounts for the difference.
30 #ifndef NO_LONGJMP
31 # define FAIL_RETURN(returnCode)
32 # define TPM_FAIL_RETURN NORETURN void
33 #else
34 # define FAIL_RETURN(returnCode) return (returnCode)
35 # define TPM_FAIL_RETURN void
36 #endif
This macro tests that a condition is TRUE and puts the TPM into failure mode if it is not. If longjmp is
being used, then the FAIL(FATAL_ERROR_) macro makes a call from which there is no return.
Otherwise, it returns and the function will exit with the appropriate return code.
In some cases, the relationship between two values may be dependent on things that change based on
various selections like the chosen cryptographic libraries. It is possible that these selections will result in
incompatible settings. These are often detectable by the compiler but it isn't always possible to do the
check in the preprocessor code. For example, when the check requires use of sizeof then the
preprocessor can't do the comparison. For these cases, we include a special macro that, depending on
the compiler will generate a warning to indicate if the check always passes or always fails because it
involves fixed constants. To run these checks, define COMPILER_CHECKS in TpmBuildSwitches.h
57 #if COMPILER_CHECKS
58 # define cAssert pAssert
59 #else
60 # define cAssert(value)
61 #endif
This is used commonly in the Crypt code as a way to keep listings from getting too long. This is not to
save paper but to allow one to see more useful stuff on the screen at any given time.
62 #define ERROR_RETURN(returnCode) \
63 { \
64 retVal = returnCode; \
65 goto Exit; \
66 }
67 #ifndef MAX
68 # define MAX(a, b) ((a) > (b) ? (a) : (b))
69 #endif
70 #ifndef MIN
71 # define MIN(a, b) ((a) < (b) ? (a) : (b))
72 #endif
73 #ifndef IsOdd
These are defined for use when the size of the vector being checked is known at compile time.
The following definitions are used if they have not already been defined. The defaults for these settings
are compatible with ISO/IEC 9899:2011 (E)
82 #ifndef LIB_EXPORT
83 # define LIB_EXPORT
84 # define LIB_IMPORT
85 #endif
86 #ifndef NORETURN
87 # define NORETURN _Noreturn
88 #endif
89 #ifndef NOT_REFERENCED
90 # define NOT_REFERENCED(x = x) ((void) (x))
91 #endif
92 #define STD_RESPONSE_HEADER (sizeof(TPM_ST) + sizeof(UINT32) + sizeof(TPM_RC))
93 #define JOIN(x, y) x##y
94 #define JOIN3(x, y, z) x##y##z
95 #define CONCAT(x, y) JOIN(x, y)
96 #define CONCAT3(x, y, z) JOIN3(x,y,z)
If CONTEXT_INTEGRITY_HASH_ALG is defined, then the vendor is using the old style table. Otherwise,
pick the strongest implemented hash algorithm as the context hash.
97 #ifndef CONTEXT_HASH_ALGORITHM
98 # if defined ALG_SHA512 && ALG_SHA512 == YES
99 # define CONTEXT_HASH_ALGORITHM SHA512
100 # elif defined ALG_SHA384 && ALG_SHA384 == YES
101 # define CONTEXT_HASH_ALGORITHM SHA384
102 # elif defined ALG_SHA256 && ALG_SHA256 == YES
103 # define CONTEXT_HASH_ALGORITHM SHA256
104 # elif defined ALG_SM3_256 && ALG_SM3_256 == YES
105 # define CONTEXT_HASH_ALGORITHM SM3_256
106 # elif defined ALG_SHA1 && ALG_SHA1 == YES
107 # define CONTEXT_HASH_ALGORITHM SHA1
108 # endif
109 # define CONTEXT_INTEGRITY_HASH_ALG CONCAT(TPM_ALG_, CONTEXT_HASH_ALGORITHM)
110 #endif
111 #ifndef CONTEXT_INTEGRITY_HASH_SIZE
112 #define CONTEXT_INTEGRITY_HASH_SIZE CONCAT(CONTEXT_HASH_ALGORITHM, _DIGEST_SIZE)
113 #endif
114 #if ALG_RSA
115 #define RSA_SECURITY_STRENGTH (MAX_RSA_KEY_BITS >= 15360 ? 256 : \
116 (MAX_RSA_KEY_BITS >= 7680 ? 192 : \
117 (MAX_RSA_KEY_BITS >= 3072 ? 128 : \
118 (MAX_RSA_KEY_BITS >= 2048 ? 112 : \
119 (MAX_RSA_KEY_BITS >= 1024 ? 80 : 0)))))
120 #else
121 #define RSA_SECURITY_STRENGTH 0
122 #endif // ALG_RSA
123 #if ALG_ECC
124 #define ECC_SECURITY_STRENGTH (MAX_ECC_KEY_BITS >= 521 ? 256 : \
125 (MAX_ECC_KEY_BITS >= 384 ? 192 : \
126 (MAX_ECC_KEY_BITS >= 256 ? 128 : 0)))
127 #else
128 #define ECC_SECURITY_STRENGTH 0
129 #endif // ALG_ECC
130 #define MAX_ASYM_SECURITY_STRENGTH \
131 MAX(RSA_SECURITY_STRENGTH, ECC_SECURITY_STRENGTH)
132 #define MAX_HASH_SECURITY_STRENGTH ((CONTEXT_INTEGRITY_HASH_SIZE * 8) / 2)
This is the size that was used before the 1.38 errata requiring that P1.14.4 be followed
As required by P1.14.4
As required by P1.14.3.1
If CONTEXT_ENCRYPT_ALG is defined, then the vendor is using the old style table
This is updated to follow the requirement of P2 that the label not be larger than 32 bytes.
This bit is used to indicate that an authorization ticket expires on TPM Reset and TPM Restart. It is added
to the timeout value returned by TPM2_PoliySigned() and TPM2_PolicySecret() and used by
TPM2_PolicyTicket(). The timeout value is relative to Time (g_time). Time is reset whenever the TPM
loses power and cannot be moved forward by the user (as can Clock). g_time is a 64-bit value expressing
time in ms. Stealing the MSb for a flag means that the TPM needs to be reset at least once every
292,471,208 years rather than once every 584,942,417 years.
These macros are used to handle the variation in handling of bit fields. If
187 #if USE_BIT_FIELD_STRUCTURES // The default, old version, with bit fields
188 # define IS_ATTRIBUTE(a, type, b) ((a.b) != 0)
189 # define SET_ATTRIBUTE(a, type, b) (a.b = SET)
190 # define CLEAR_ATTRIBUTE(a, type, b) (a.b = CLEAR)
191 # define GET_ATTRIBUTE(a, type, b) (a.b)
192 # define TPMA_ZERO_INITIALIZER() {0}
193 #else
194 # define IS_ATTRIBUTE(a, type, b) ((a & type##_##b) != 0)
195 # define SET_ATTRIBUTE(a, type, b) (a |= type##_##b)
196 # define CLEAR_ATTRIBUTE(a, type, b) (a &= ~type##_##b)
197 # define GET_ATTRIBUTE(a, type, b) \
198 (type)((a & type##_##b) >> type##_##b##_SHIFT)
199 # define TPMA_ZERO_INITIALIZER() (0)
200 #endif
201 #define VERIFY(_X) if(!(_X)) goto Error
These macros determine if the values in this file are referenced or instanced. Global.c defines
GLOBAL_C so all the values in this file will be instanced in Global.obj. For all other files that include this
file, the values will simply be external references. For constants, there can be an initializer.
This macro will create an OID. All OIDs are in DER form with a first octet of 0x06 indicating an OID
fallowed by an octet indicating the number of octets in the rest of the OID. This allows a user of this OID
to know how much/little to copy.
This definition is moved from TpmProfile.h because it is not actually vendor- specific. It has to be the
same size as the sequence parameter of a TPMS_CONTEXT and that is a UINT64. So, this is an
invariant value
5.11 InternalRoutines.h
1 #ifndef INTERNAL_ROUTINES_H
2 #define INTERNAL_ROUTINES_H
3 #if !defined _LIB_SUPPORT_H_ && !defined _TPM_H_
4 #error "Should not be called"
5 #endif
DRTM functions
6 #include "_TPM_Hash_Start_fp.h"
7 #include "_TPM_Hash_Data_fp.h"
8 #include "_TPM_Hash_End_fp.h"
9 #include "Object_fp.h"
10 #include "Context_spt_fp.h"
11 #include "Object_spt_fp.h"
12 #include "Entity_fp.h"
13 #include "Session_fp.h"
14 #include "Hierarchy_fp.h"
15 #include "NvReserved_fp.h"
16 #include "NvDynamic_fp.h"
17 #include "NV_spt_fp.h"
18 #include "ACT_spt_fp.h"
19 #include "PCR_fp.h"
20 #include "DA_fp.h"
21 #include "TpmFail_fp.h"
22 #include "SessionProcess_fp.h"
23 #include "CommandCodeAttributes_fp.h"
24 #include "Marshal.h"
25 #include "Time_fp.h"
26 #include "Locality_fp.h"
27 #include "PP_fp.h"
28 #include "CommandAudit_fp.h"
29 #include "Manufacture_fp.h"
30 #include "Handle_fp.h"
31 #include "Power_fp.h"
32 #include "Response_fp.h"
33 #include "CommandDispatcher_fp.h"
34 #ifdef CC_AC_Send
35 # include "AC_spt_fp.h"
36 #endif // CC_AC_Send
Miscellaneous
37 #include "Bits_fp.h"
38 #include "AlgorithmCap_fp.h"
39 #include "PropertyCap_fp.h"
40 #include "IoBuffers_fp.h"
41 #include "Memory_fp.h"
42 #include "ResponseCodeProcessing_fp.h"
43 #include "BnConvert_fp.h"
44 #include "BnMath_fp.h"
45 #include "BnMemory_fp.h"
46 #include "Ticket_fp.h"
47 #include "CryptUtil_fp.h"
48 #include "CryptHash_fp.h"
49 #include "CryptSym_fp.h"
50 #include "CryptDes_fp.h"
51 #include "CryptPrime_fp.h"
52 #include "CryptRand_fp.h"
53 #include "CryptSelfTest_fp.h"
54 #include "MathOnByteBuffers_fp.h"
55 #include "CryptSym_fp.h"
56 #include "AlgorithmTests_fp.h"
57 #if ALG_RSA
58 #include "CryptRsa_fp.h"
59 #include "CryptPrimeSieve_fp.h"
60 #endif
61 #if ALG_ECC
62 #include "CryptEccMain_fp.h"
63 #include "CryptEccSignature_fp.h"
64 #include "CryptEccKeyExchange_fp.h"
65 #endif
66 #if CC_MAC || CC_MAC_Start
67 # include "CryptSmac_fp.h"
68 # if ALG_CMAC
69 # include "CryptCmac_fp.h"
70 # endif
71 #endif
Support library
72 #include "SupportLibraryFunctionPrototypes_fp.h"
73 #include "Platform_fp.h"
74 #endif
5.12 LibSupport.h
This header file is used to select the library code that gets included in the TPM build.
1 #ifndef _LIB_SUPPORT_H_
2 #define _LIB_SUPPORT_H_
3 #ifndef RADIX_BITS
4 # if defined(__x86_64__) || defined(__x86_64)
\
5 || defined(__amd64__) || defined(__amd64) || defined(_WIN64) ||
defined(_M_X64) \
6 || defined(_M_ARM64) || defined(__aarch64__)
7 # define RADIX_BITS 64
8 # elif defined(__i386__) || defined(__i386) || defined(i386)
\
9 || defined(_WIN32) || defined(_M_IX86)
\
10 || defined(_M_ARM) || defined(__arm__) || defined(__thumb__)
11 # define RADIX_BITS 32
12 # else
13 # error Unable to determine RADIX_BITS from compiler environment
14 # endif
15 #endif // RADIX_BITS
These macros use the selected libraries to the proper include files.
Include the options for hashing and symmetric. Defer the load of the math package Until the bignum
parameters are defined.
5.13 MinMax.h
1 #ifndef _MIN_MAX_H_
2 #define _MIN_MAX_H_
3 #ifndef MAX
4 #define MAX(a, b) ((a) > (b) ? (a) : (b))
5 #endif
6 #ifndef MIN
7 #define MIN(a, b) ((a) < (b) ? (a) : (b))
8 #endif
9 #endif // _MIN_MAX_H_
5.14 NV.h
These definitions allow the same code to be used pre and post 1.21. The main action is to redefine the
index type values from the bit values. Use TPM_NT_ORDINARY to indicate if the TPM_NT type is
defined
1 #ifndef _NV_H_
2 #define _NV_H_
3 #ifdef TPM_NT_ORDINARY
6 # define GetNv_TPM_NV(attributes) \
7 ( IS_ATTRIBUTE(attributes, TPMA_NV, COUNTER) \
8 + (IS_ATTRIBUTE(attributes, TPMA_NV, BITS) << 1) \
9 + (IS_ATTRIBUTE(attributes, TPMA_NV, EXTEND) << 2) \
10 )
11 # define TPM_NT_ORDINARY (0)
12 # define TPM_NT_COUNTER (1)
13 # define TPM_NT_BITS (2)
14 # define TPM_NT_EXTEND (4)
15 #endif
These macros are used to isolate the differences in the way that the index type changed in version 1.21
of the specification
16 # define IsNvOrdinaryIndex(attributes) \
17 (GET_TPM_NT(attributes) == TPM_NT_ORDINARY)
18 # define IsNvCounterIndex(attributes) \
19 (GET_TPM_NT(attributes) == TPM_NT_COUNTER)
20 # define IsNvBitsIndex(attributes) \
21 (GET_TPM_NT(attributes) == TPM_NT_BITS)
22 # define IsNvExtendIndex(attributes) \
23 (GET_TPM_NT(attributes) == TPM_NT_EXTEND)
24 #ifdef TPM_NT_PIN_PASS
25 # define IsNvPinPassIndex(attributes) \
26 (GET_TPM_NT(attributes) == TPM_NT_PIN_PASS)
27 #endif
28 #ifdef TPM_NT_PIN_FAIL
29 # define IsNvPinFailIndex(attributes) \
30 (GET_TPM_NT(attributes) == TPM_NT_PIN_FAIL)
31 #endif
32 typedef struct {
33 UINT32 size;
34 TPM_HANDLE handle;
35 } NV_ENTRY_HEADER;
36 #define NV_EVICT_OBJECT_SIZE \
37 (sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(OBJECT))
38 #define NV_INDEX_COUNTER_SIZE \
39 (sizeof(UINT32) + sizeof(NV_INDEX) + sizeof(UINT64))
40 #define NV_RAM_INDEX_COUNTER_SIZE \
41 (sizeof(NV_RAM_HEADER) + sizeof(UINT64))
42 typedef struct {
43 UINT32 size;
44 TPM_HANDLE handle;
45 TPMA_NV attributes;
46 } NV_RAM_HEADER;
Defines the end-of-list marker for NV. The list terminator is a UINT32 of zero, followed by the current
value of s_maxCounter which is a 64-bit value. The structure is defined as an array of 3 UINT32 values
so that there is no padding between the UINT32 list end marker and the UINT64 maxCounter value.
The following defines are for accessing orderly RAM values. This is the initialize for the RAM reference
iterator.
48 #define NV_RAM_REF_INIT 0
This is the starting address of the RAM space used for orderly data
49 #define RAM_ORDERLY_START \
50 (&s_indexOrderlyRam[0])
This is the offset within NV that is used to save the orderly data on an orderly shutdown.
51 #define NV_ORDERLY_START \
52 (NV_INDEX_RAM_DATA)
This is the end of the orderly RAM space. It is actually the first byte after the last byte of orderly RAM data
53 #define RAM_ORDERLY_END \
54 (RAM_ORDERLY_START + sizeof(s_indexOrderlyRam))
This is the end of the orderly space in NV memory. As with RAM_ORDERLY_END, it is actually the offset
of the first byte after the end of the NV orderly data.
55 #define NV_ORDERLY_END \
56 (NV_ORDERLY_START + sizeof(s_indexOrderlyRam))
Routinely have to clear the orderly flag and fail if the NV is not available so that it can be cleared.
64 #define RETURN_IF_ORDERLY \
65 { \
66 if(NvClearOrderly() != TPM_RC_SUCCESS) \
67 return g_NvStatus; \
68 }
69 #define NV_IS_AVAILABLE (g_NvStatus == TPM_RC_SUCCESS)
70 #define IS_ORDERLY(value) (value < SU_DA_USED_VALUE)
71 #define NV_IS_ORDERLY (IS_ORDERLY(gp.orderlyState))
Macro to set the NV UPDATE_TYPE. This deals with the fact that the update is possibly a combination of
UT_NV and UT_ORDERLY.
5.15 TPMB.h
1 #ifndef _TPMB_H
2 #define _TPMB_H
TPM2B Types
3 typedef struct {
4 UINT16 size;
5 BYTE buffer[1];
6 } TPM2B, *P2B;
7 typedef const TPM2B *PC2B;
This macro helps avoid having to type in the structure in order to create a new TPM2B type that is used in
a function.
This macro defines a TPM2B with a constant character value. This macro sets the size of the string to the
size minus the terminating zero byte. This lets the user of the label add their terminating 0. This method is
chosen so that existing code that provides a label will continue to work correctly. Macro to instance and
initialize a TPM2B value
5.16 Tpm.h
1 #ifndef _TPM_H_
2 #define _TPM_H_
3 #include "TpmBuildSwitches.h"
4 #include "BaseTypes.h"
5 #include "TPMB.h"
6 #include "MinMax.h"
7 #include "TpmProfile.h"
8 #include "TpmAlgorithmDefines.h"
9 #include "LibSupport.h" // Types from the library. These need to come before
10 // Global.h because some of the structures in
11 // that file depend on the structures used by the
12 // cryptographic libraries.
13 #include "GpMacros.h" // Define additional macros
14 #include "Global.h" // Define other TPM types
15 #include "InternalRoutines.h" // Function prototypes
16 #endif // _TPM_H_
5.17 TpmBuildSwitches.h
This file contains the build switches. This contains switches for multiple versions of the crypto-library so
some may not apply to your environment.
The switches are guarded so that they can either be set on the command line or set here. If the switch is
listed on the command line (-DSOME_SWITCH) with NO setting, then the switch will be set to YES. If the
switch setting is not on the command line or if the setting is other than YES or NO, then the switch will be
set to the default value. The default can either be YES or NO as indicated on each line where the default
is selected.
A caution. Do not try to test these macros by inserting #defines in this file. For some curious reason, a
variable set on the command line with no setting will have a value of 1. An #if SOME_VARIABLE will work
if the variable is not defined or is defined on the command line with no initial setting. However, a "#define
SOME_VARIABLE" is a null string and when used in "#if SOME_VARIABLE" will not be a proper
expression If you want to test various switches, either use the command line or change the default.
1 #ifndef _TPM_BUILD_SWITCHES_H_
2 #define _TPM_BUILD_SWITCHES_H_
3 #undef YES
4 #define YES 1
5 #undef NO
6 #define NO 0
7 #ifdef PROFILE
8 # define PROFILE_QUOTE(a) #a
9 # define PROFILE_INCLUDE(a) PROFILE_QUOTE(a)
10 # include PROFILE_INCLUDE(PROFILE)
11 #endif
12 #ifndef DEBUG
13 # ifdef NDEBUG
14 # define DEBUG NO
15 # else
16 # define DEBUG YES
17 # endif
18 #elif (DEBUG != NO) && (DEBUG != YES)
19 # undef DEBUG
20 # define DEBUG YES // Default: Either YES or NO
21 #endif
22 #include "CompilerDependencies.h"
The SIMULATION switch allows certain other macros to be enabled. The things that can be enabled in a
simulation include key caching, reproducible random sequences, instrumentation of the RSA key
generation process, and certain other debug code. SIMULATION Needs to be defined as either YES or
NO. This grouping of macros will make sure that it is set correctly. A simulated TPM would include a
Virtual TPM. The interfaces for a Virtual TPM should be modified from the standard ones in the Simulator
project.
Define this to run the function that checks the compatibility between the chosen big number math library
and the TPM code. Not all ports use this.
Definition to allow alternate behavior for non-orderly startup. If there is a chance that the TPM could not
update failedTries
Define TABLE_DRIVEN_DISPATCH to use tables rather than case statements for command dispatch
and handle unmarshaling
Enable the instrumentation of the sieve process. This is used to tune the sieve variables.
Switch added to support packed lists that leave out space associated with unimplemented commands.
Comment this out to use linear lists.
NOTE: if vendor specific commands are present, the associated list is always in compressed form.
This switch indicates where clock epoch value should be stored. If this value defined, then it is assumed
that the timer will change at any time so the nonce should be a random number kept in RAM. When it is
not defined, then the timer only stops during power outages.
This switch allows use of #defines in place of pass-through marshaling or unmarshaling code. A pass-
through function just calls another function to do the required function and does no parameter checking of
its own. The table-driven dispatcher calls directly to the lowest level marshaling/unmarshaling code and
by-passes any pass-through functions.
The switches in this group can only be enabled when doing debug during simulation
This forces the use of a smaller context slot size. This reduction reduces the range of the epoch allowing
the tester to force the epoch to occur faster than the normal defined in TpmProfile.h
87 # if !(defined CONTEXT_SLOT)
88 # define CONTEXT_SLOT UINT8
89 # endif
90 # if !(defined USE_RSA_KEY_CACHE) \
91 || ((USE_RSA_KEY_CACHE != NO) && (USE_RSA_KEY_CACHE != YES))
92 # undef USE_RSA_KEY_CACHE
93 # define USE_RSA_KEY_CACHE YES // Default: Either YES or NO
94 # endif
Enables use of a file to store the key cache values so that the TPM will start faster during debug. Default
for this is YES
95 # if USE_RSA_KEY_CACHE
96 # if !(defined USE_KEY_CACHE_FILE) \
97 || ((USE_KEY_CACHE_FILE != NO) && (USE_KEY_CACHE_FILE != YES))
98 # undef USE_KEY_CACHE_FILE
99 # define USE_KEY_CACHE_FILE YES // Default: Either YES or NO
100 # endif
101 # else
102 # undef USE_KEY_CACHE_FILE
103 # define USE_KEY_CACHE_FILE NO
104 # endif // USE_RSA_KEY_CACHE
This provides fixed seeding of the RNG when doing debug on a simulator. This should allow consistent
results on test runs as long as the input parameters to the functions remains the same. There is no
default value.
Don't change these. They are the settings needed when not doing a simulation and not doing debug.
Can't use the key cache except during debug. Otherwise, all of the key values end up being the same
109 #else
110 # define USE_RSA_KEY_CACHE NO
111 # define USE_RSA_KEY_CACHE_FILE NO
112 # define USE_DEBUG_RNG NO
113 #endif // DEBUG && SIMULATION
114 #if DEBUG
In some cases, the relationship between two values may be dependent on things that change based on
various selections like the chosen cryptographic libraries. It is possible that these selections will result in
incompatible settings. These are often detectable by the compiler but it isn't always possible to do the
check in the preprocessor code. For example, when the check requires use of 'sizeof()' then the
preprocessor can't do the comparison. For these cases, we include a special macro that, depending on
the compiler will generate a warning to indicate if the check always passes or always fails because it
involves fixed constants. To run these checks, define COMPILER_CHECKS.
Some of the values (such as sizes) are the result of different options set in TpmProfile.h. The combination
might not be consistent. A function is defined (TpmSizeChecks()) that is used to verify the sizes at run
time. To enable the function, define this parameter.
If doing debug, can set the DRBG to print out the intermediate test values. Before enabling this, make
sure that the dbgDumpMemBlock() function has been added someplace (preferably, somewhere in
CryptRand.c)
If an assertion event it not going to produce any trace information (function and line number) then make
FAIL_TRACE == NO
Indicate if the implementation is going to give lockout time credit for time up to the last orderly shutdown.
Indicates if the implementation is to compute the sizes of the proof and primary seed size values based
on the implemented algorithms.
Comment this out to allow compile to continue even though the chosen proof values do not match the
compliant values. This is written so that someone would have to proactively ignore errors.
This define is used to eliminate the use of bit-fields. It can be enabled for big- or little-endian machines.
For big-endian architectures that numbers bits in registers from left to right (MSb0) this must be enabled.
Little-endian machines number from right to left with the least significant bit having assigned a bit number
of 0. These are LSb0 machines (they are also little-endian so they are also least-significant byte 0 (LSB0)
machines. Big-endian (MSB0) machines may number in either direction (MSb0 or LSb0). For an
MSB0+MSb0 machine this value is required to be NO
This define is used to control the debug for the CertifyX509() command.
Change these definitions to turn all algorithms or commands ON or OFF. That is, to turn all algorithms on,
set ALG_NO to YES. This is mostly useful as a debug feature.
5.18 TpmError.h
1 #ifndef _TPM_ERROR_H
2 #define _TPM_ERROR_H
3 #define FATAL_ERROR_ALLOCATION (1)
4 #define FATAL_ERROR_DIVIDE_ZERO (2)
5 #define FATAL_ERROR_INTERNAL (3)
6 #define FATAL_ERROR_PARAMETER (4)
7 #define FATAL_ERROR_ENTROPY (5)
8 #define FATAL_ERROR_SELF_TEST (6)
9 #define FATAL_ERROR_CRYPTO (7)
10 #define FATAL_ERROR_NV_UNRECOVERABLE (8)
11 #define FATAL_ERROR_REMANUFACTURED (9) // indicates that the TPM has
12 // been re-manufactured after an
13 // unrecoverable NV error
14 #define FATAL_ERROR_DRBG (10)
15 #define FATAL_ERROR_MOVE_SIZE (11)
16 #define FATAL_ERROR_COUNTER_OVERFLOW (12)
17 #define FATAL_ERROR_SUBTRACT (13)
18 #define FATAL_ERROR_MATHLIBRARY (14)
19 #define FATAL_ERROR_FORCED (666)
20 #endif // _TPM_ERROR_H
5.19 TpmTypes.h
1 #ifndef _TPM_TYPES_H_
2 #define _TPM_TYPES_H_
1182 TPM2B b;
1183 } TPM2B_EVENT; /* Structure */
1184 typedef union { // Table 2:87
1185 struct {
1186 UINT16 size;
1187 BYTE buffer[MAX_DIGEST_BUFFER];
1188 } t;
1189 TPM2B b;
1190 } TPM2B_MAX_BUFFER; /* Structure */
1191 typedef union { // Table 2:88
1192 struct {
1193 UINT16 size;
1194 BYTE buffer[MAX_NV_BUFFER_SIZE];
1195 } t;
1196 TPM2B b;
1197 } TPM2B_MAX_NV_BUFFER; /* Structure */
1198 typedef union { // Table 2:89
1199 struct {
1200 UINT16 size;
1201 BYTE buffer[sizeof(UINT64)];
1202 } t;
1203 TPM2B b;
1204 } TPM2B_TIMEOUT; /* Structure */
1205 typedef union { // Table 2:90
1206 struct {
1207 UINT16 size;
1208 BYTE buffer[MAX_SYM_BLOCK_SIZE];
1209 } t;
1210 TPM2B b;
1211 } TPM2B_IV; /* Structure */
1212 typedef union { // Table 2:91
1213 TPMT_HA digest;
1214 TPM_HANDLE handle;
1215 } TPMU_NAME; /* Structure */
1216 typedef union { // Table 2:92
1217 struct {
1218 UINT16 size;
1219 BYTE name[sizeof(TPMU_NAME)];
1220 } t;
1221 TPM2B b;
1222 } TPM2B_NAME; /* Structure */
1223 typedef struct { // Table 2:93
1224 UINT8 sizeofSelect;
1225 BYTE pcrSelect[PCR_SELECT_MAX];
1226 } TPMS_PCR_SELECT; /* Structure */
1227 typedef struct { // Table 2:94
1228 TPMI_ALG_HASH hash;
1229 UINT8 sizeofSelect;
1230 BYTE pcrSelect[PCR_SELECT_MAX];
1231 } TPMS_PCR_SELECTION; /* Structure */
1232 typedef struct { // Table 2:97
1233 TPM_ST tag;
1234 TPMI_RH_HIERARCHY hierarchy;
1235 TPM2B_DIGEST digest;
1236 } TPMT_TK_CREATION; /* Structure */
1237 typedef struct { // Table 2:98
1238 TPM_ST tag;
1239 TPMI_RH_HIERARCHY hierarchy;
1240 TPM2B_DIGEST digest;
1241 } TPMT_TK_VERIFIED; /* Structure */
1242 typedef struct { // Table 2:99
1243 TPM_ST tag;
1244 TPMI_RH_HIERARCHY hierarchy;
1245 TPM2B_DIGEST digest;
1246 } TPMT_TK_AUTH; /* Structure */
1247 typedef struct { // Table 2:100
1512 TPM2B b;
1513 } TPM2B_SENSITIVE_DATA; /* Structure */
1514 typedef struct { // Table 2:150
1515 TPM2B_AUTH userAuth;
1516 TPM2B_SENSITIVE_DATA data;
1517 } TPMS_SENSITIVE_CREATE; /* Structure */
1518 typedef struct { // Table 2:151
1519 UINT16 size;
1520 TPMS_SENSITIVE_CREATE sensitive;
1521 } TPM2B_SENSITIVE_CREATE; /* Structure */
1522 typedef struct { // Table 2:152
1523 TPMI_ALG_HASH hashAlg;
1524 } TPMS_SCHEME_HASH; /* Structure */
1525 typedef struct { // Table 2:153
1526 TPMI_ALG_HASH hashAlg;
1527 UINT16 count;
1528 } TPMS_SCHEME_ECDAA; /* Structure */
1529 typedef TPM_ALG_ID TPMI_ALG_KEYEDHASH_SCHEME;
1879 struct {
1880 UINT16 size;
1881 BYTE buffer[sizeof(_PRIVATE)];
1882 } t;
1883 TPM2B b;
1884 } TPM2B_PRIVATE; /* Structure */
1885 typedef struct { // Table 2:210
1886 TPM2B_DIGEST integrityHMAC;
1887 TPM2B_DIGEST encIdentity;
1888 } TPMS_ID_OBJECT; /* Structure */
1889 typedef union { // Table 2:211
1890 struct {
1891 UINT16 size;
1892 BYTE credential[sizeof(TPMS_ID_OBJECT)];
1893 } t;
1894 TPM2B b;
1895 } TPM2B_ID_OBJECT; /* Structure */
1896 #define TYPE_OF_TPM_NV_INDEX UINT32
1897 #define TPM_NV_INDEX_TO_UINT32(a) (*((UINT32 *)&(a)))
1898 #define UINT32_TO_TPM_NV_INDEX(a) (*((TPM_NV_INDEX *)&(a)))
1899 #define TPM_NV_INDEX_TO_BYTE_ARRAY(i, a) \
1900 UINT32_TO_BYTE_ARRAY((TPM_NV_INDEX_TO_UINT32(i)), (a))
1901 #define BYTE_ARRAY_TO_TPM_NV_INDEX(i, a) \
1902 { UINT32 x = BYTE_ARRAY_TO_UINT32(a); i = UINT32_TO_TPM_NV_INDEX(x); }
1903 #if USE_BIT_FIELD_STRUCTURES
1904 typedef struct TPM_NV_INDEX { // Table 2:212
1905 unsigned index : 24;
1906 unsigned RH_NV : 8;
1907 } TPM_NV_INDEX; /* Bits */
5.20 VendorString.h
1 #ifndef _VENDOR_STRING_H
2 #define _VENDOR_STRING_H
Define up to 4-byte values for MANUFACTURER. This value defines the response for
TPM_PT_MANUFACTURER in TPM2_GetCapability(). The following line should be un-commented and a
vendor specific string should be provided here.
The following #if macro may be deleted after a proper MANUFACTURER is provided.
4 #ifndef MANUFACTURER
5 #error MANUFACTURER is not provided. \
6 Please modify include/VendorString.h to provide a specific \
7 manufacturer name.
8 #endif
Define up to 4, 4-byte values. The values must each be 4 bytes long and the last value used may contain
trailing zeros. These values define the response for TPM_PT_VENDOR_STRING_(1-4) in
TPM2_GetCapability(). The following line should be un-commented and a vendor specific string should
be provided here. The vendor strings 2-4 may also be defined as appropriate.
The following #if macro may be deleted after a proper VENDOR_STRING_1 is provided.
13 #ifndef VENDOR_STRING_1
14 #error VENDOR_STRING_1 is not provided. \
15 Please modify include/VendorString.h to provide a vendor-specific string.
16 #endif
the more significant 32-bits of a vendor-specific value indicating the version of the firmware The following
line should be un-commented and a vendor specific firmware V1 should be provided here. The
FIRMWARE_V2 may also be defined as appropriate.
the less significant 32-bits of a vendor-specific value indicating the version of the firmware
The following #if macro may be deleted after a proper FIRMWARE_V1 is provided.
19 #ifndef FIRMWARE_V1
20 #error FIRMWARE_V1 is not provided. \
21 Please modify include/VendorString.h to provide a vendor-specific firmware \
22 version
23 #endif
24 #endif
5.21 swap.h
1 #ifndef _SWAP_H
2 #define _SWAP_H
3 #if LITTLE_ENDIAN_TPM
4 #define TO_BIG_ENDIAN_UINT16(i) REVERSE_ENDIAN_16(i)
5 #define FROM_BIG_ENDIAN_UINT16(i) REVERSE_ENDIAN_16(i)
6 #define TO_BIG_ENDIAN_UINT32(i) REVERSE_ENDIAN_32(i)
7 #define FROM_BIG_ENDIAN_UINT32(i) REVERSE_ENDIAN_32(i)
8 #define TO_BIG_ENDIAN_UINT64(i) REVERSE_ENDIAN_64(i)
9 #define FROM_BIG_ENDIAN_UINT64(i) REVERSE_ENDIAN_64(i)
10 #else
11 #define TO_BIG_ENDIAN_UINT16(i) (i)
12 #define FROM_BIG_ENDIAN_UINT16(i) (i)
13 #define TO_BIG_ENDIAN_UINT32(i) (i)
14 #define FROM_BIG_ENDIAN_UINT32(i) (i)
15 #define TO_BIG_ENDIAN_UINT64(i) (i)
16 #define FROM_BIG_ENDIAN_UINT64(i) (i)
17 #endif
18 #if AUTO_ALIGN == NO
The aggregation macros for machines that do not allow unaligned access or for little-endian machines.
Aggregate bytes into an UINT
the big-endian macros for machines that allow unaligned memory access Aggregate a byte array into a
UINT
the little endian macros for machines that allow unaligned memory access the big-endian macros for
machines that allow unaligned memory access Aggregate a byte array into a UINT
5.22 ACT.h
1 #ifndef _ACT_H_
2 #define _ACT_H_
3 #include "TpmProfile.h"
4 #if !(defined RH_ACT_0) || (RH_ACT_0 != YES)
5 # undef RH_ACT_0
6 # define RH_ACT_0 NO
7 # define IF_ACT_0_IMPLEMENTED(op)
8 #else
9 # define IF_ACT_0_IMPLEMENTED(op) op(0)
10 #endif
11 #if !(defined RH_ACT_1) || (RH_ACT_1 != YES)
12 # undef RH_ACT_1
13 # define RH_ACT_1 NO
14 # define IF_ACT_1_IMPLEMENTED(op)
15 #else
16 # define IF_ACT_1_IMPLEMENTED(op) op(1)
17 #endif
18 #if !(defined RH_ACT_2) || (RH_ACT_2 != YES)
19 # undef RH_ACT_2
20 # define RH_ACT_2 NO
21 # define IF_ACT_2_IMPLEMENTED(op)
22 #else
23 # define IF_ACT_2_IMPLEMENTED(op) op(2)
24 #endif
25 #if !(defined RH_ACT_3) || (RH_ACT_3 != YES)
26 # undef RH_ACT_3
27 # define RH_ACT_3 NO
28 # define IF_ACT_3_IMPLEMENTED(op)
29 #else
30 # define IF_ACT_3_IMPLEMENTED(op) op(3)
31 #endif
32 #if !(defined RH_ACT_4) || (RH_ACT_4 != YES)
33 # undef RH_ACT_4
34 # define RH_ACT_4 NO
35 # define IF_ACT_4_IMPLEMENTED(op)
36 #else
37 # define IF_ACT_4_IMPLEMENTED(op) op(4)
38 #endif
39 #if !(defined RH_ACT_5) || (RH_ACT_5 != YES)
40 # undef RH_ACT_5
41 # define RH_ACT_5 NO
42 # define IF_ACT_5_IMPLEMENTED(op)
43 #else
44 # define IF_ACT_5_IMPLEMENTED(op) op(5)
45 #endif
46 #if !(defined RH_ACT_6) || (RH_ACT_6 != YES)
47 # undef RH_ACT_6
48 # define RH_ACT_6 NO
49 # define IF_ACT_6_IMPLEMENTED(op)
50 #else
51 # define IF_ACT_6_IMPLEMENTED(op) op(6)
52 #endif
53 #if !(defined RH_ACT_7) || (RH_ACT_7 != YES)
54 # undef RH_ACT_7
55 # define RH_ACT_7 NO
56 # define IF_ACT_7_IMPLEMENTED(op)
57 #else
58 # define IF_ACT_7_IMPLEMENTED(op) op(7)
59 #endif
60 #if !(defined RH_ACT_8) || (RH_ACT_8 != YES)
61 # undef RH_ACT_8
62 # define RH_ACT_8 NO
63 # define IF_ACT_8_IMPLEMENTED(op)
64 #else
65 # define IF_ACT_8_IMPLEMENTED(op) op(8)
66 #endif
67 #if !(defined RH_ACT_9) || (RH_ACT_9 != YES)
68 # undef RH_ACT_9
69 # define RH_ACT_9 NO
70 # define IF_ACT_9_IMPLEMENTED(op)
71 #else
72 # define IF_ACT_9_IMPLEMENTED(op) op(9)
73 #endif
74 #if !(defined RH_ACT_A) || (RH_ACT_A != YES)
75 # undef RH_ACT_A
76 # define RH_ACT_A NO
77 # define IF_ACT_A_IMPLEMENTED(op)
78 #else
79 # define IF_ACT_A_IMPLEMENTED(op) op(A)
80 #endif
81 #if !(defined RH_ACT_B) || (RH_ACT_B != YES)
82 # undef RH_ACT_B
83 # define RH_ACT_B NO
84 # define IF_ACT_B_IMPLEMENTED(op)
85 #else
86 # define IF_ACT_B_IMPLEMENTED(op) op(B)
87 #endif
88 #if !(defined RH_ACT_C) || (RH_ACT_C != YES)
89 # undef RH_ACT_C
90 # define RH_ACT_C NO
91 # define IF_ACT_C_IMPLEMENTED(op)
92 #else
93 # define IF_ACT_C_IMPLEMENTED(op) op(C)
94 #endif
95 #if !(defined RH_ACT_D) || (RH_ACT_D != YES)
96 # undef RH_ACT_D
97 # define RH_ACT_D NO
98 # define IF_ACT_D_IMPLEMENTED(op)
99 #else
100 # define IF_ACT_D_IMPLEMENTED(op) op(D)
101 #endif
102 #if !(defined RH_ACT_E) || (RH_ACT_E != YES)
103 # undef RH_ACT_E
104 # define RH_ACT_E NO
105 # define IF_ACT_E_IMPLEMENTED(op)
106 #else
107 # define IF_ACT_E_IMPLEMENTED(op) op(E)
108 #endif
109 #if !(defined RH_ACT_F) || (RH_ACT_F != YES)
110 # undef RH_ACT_F
111 # define RH_ACT_F NO
112 # define IF_ACT_F_IMPLEMENTED(op)
113 #else
114 # define IF_ACT_F_IMPLEMENTED(op) op(F)
115 #endif
116 #ifndef TPM_RH_ACT_0
117 #error Need numeric definition for TPM_RH_ACT_0
118 #endif
119 #ifndef TPM_RH_ACT_1
120 # define TPM_RH_ACT_1 (TPM_RH_ACT_0 + 1)
121 #endif
122 #ifndef TPM_RH_ACT_2
123 # define TPM_RH_ACT_2 (TPM_RH_ACT_0 + 2)
124 #endif
125 #ifndef TPM_RH_ACT_3
126 # define TPM_RH_ACT_3 (TPM_RH_ACT_0 + 3)
127 #endif
128 #ifndef TPM_RH_ACT_4
129 # define TPM_RH_ACT_4 (TPM_RH_ACT_0 + 4)
130 #endif
131 #ifndef TPM_RH_ACT_5
132 # define TPM_RH_ACT_5 (TPM_RH_ACT_0 + 5)
133 #endif
134 #ifndef TPM_RH_ACT_6
135 # define TPM_RH_ACT_6 (TPM_RH_ACT_0 + 6)
136 #endif
137 #ifndef TPM_RH_ACT_7
138 # define TPM_RH_ACT_7 (TPM_RH_ACT_0 + 7)
139 #endif
140 #ifndef TPM_RH_ACT_8
141 # define TPM_RH_ACT_8 (TPM_RH_ACT_0 + 8)
142 #endif
143 #ifndef TPM_RH_ACT_9
144 # define TPM_RH_ACT_9 (TPM_RH_ACT_0 + 9)
145 #endif
146 #ifndef TPM_RH_ACT_A
147 # define TPM_RH_ACT_A (TPM_RH_ACT_0 + 0xA)
148 #endif
149 #ifndef TPM_RH_ACT_B
150 # define TPM_RH_ACT_B (TPM_RH_ACT_0 + 0xB)
151 #endif
152 #ifndef TPM_RH_ACT_C
153 # define TPM_RH_ACT_C (TPM_RH_ACT_0 + 0xC)
154 #endif
155 #ifndef TPM_RH_ACT_D
156 # define TPM_RH_ACT_D (TPM_RH_ACT_0 + 0xD)
157 #endif
158 #ifndef TPM_RH_ACT_E
159 # define TPM_RH_ACT_E (TPM_RH_ACT_0 + 0xE)
160 #endif
161 #ifndef TPM_RH_ACT_F
162 # define TPM_RH_ACT_F (TPM_RH_ACT_0 + 0xF)
163 #endif
164 #define FOR_EACH_ACT(op) \
165 IF_ACT_0_IMPLEMENTED(op) \
166 IF_ACT_1_IMPLEMENTED(op) \
167 IF_ACT_2_IMPLEMENTED(op) \
168 IF_ACT_3_IMPLEMENTED(op) \
169 IF_ACT_4_IMPLEMENTED(op) \
170 IF_ACT_5_IMPLEMENTED(op) \
171 IF_ACT_6_IMPLEMENTED(op) \
172 IF_ACT_7_IMPLEMENTED(op) \
173 IF_ACT_8_IMPLEMENTED(op) \
174 IF_ACT_9_IMPLEMENTED(op) \
175 IF_ACT_A_IMPLEMENTED(op) \
176 IF_ACT_B_IMPLEMENTED(op) \
177 IF_ACT_C_IMPLEMENTED(op) \
178 IF_ACT_D_IMPLEMENTED(op) \
179 IF_ACT_E_IMPLEMENTED(op) \
180 IF_ACT_F_IMPLEMENTED(op)
6 Main
6.1 Introduction
The files in this section are the main processing blocks for the TPM. ExecuteCommand.c contains the
entry point into the TPM code and the parsing of the command header. SessionProcess.c handles the
parsing of the session area and the authorization checks, and CommandDispatch.c does the parameter
unmarshaling and command dispatch.
6.2 ExecCommand.c
6.2.1 Introduction
This file contains the entry function ExecuteCommand() which provides the main control flow for TPM
command execution.
6.2.2 Includes
1 #include "Tpm.h"
2 #include "ExecCommand_fp.h"
3 // #include "CommandResponseSizes_fp.h"
6.2.3 ExecuteCommand()
NOTE: As of February, 2016, the failure processing has been moved to the platform-specific code. When the TPM
code encounters an unrecoverable failure, it will SET g_inFailureMode and call _plat__Fail(). That function
should not return but may call ExecuteCommand().
4 LIB_EXPORT void
5 ExecuteCommand(
6 uint32_t requestSize, // IN: command buffer size
7 unsigned char *request, // IN: command buffer
8 uint32_t *responseSize, // IN/OUT: response buffer size
9 unsigned char **response // IN/OUT: response buffer
10 )
11 {
12 // Command local variables
13 UINT32 commandSize;
14 COMMAND command;
15
16 // Response local variables
17 UINT32 maxResponse = *responseSize;
18 TPM_RC result; // return code for the command
19
20 // This next function call is used in development to size the command and response
21 // buffers. The values printed are the sizes of the internal structures and
22 // not the sizes of the canonical forms of the command response structures. Also,
23 // the sizes do not include the tag, command.code, requestSize, or the authorization
24 // fields.
25 //CommandResponseSizes();
26 // Set flags for NV access state. This should happen before any other
27 // operation that may require a NV write. Note, that this needs to be done
28 // even when in failure mode. Otherwise, g_updateNV would stay SET while in
29 // Failure mode and the NV would be written on each call.
30 g_updateNV = UT_NONE;
31 g_clearOrderly = FALSE;
32 if(g_inFailureMode)
33 {
34 // Do failure mode processing
35 TpmFailureMode(requestSize, request, responseSize, response);
36 return;
37 }
38 // Query platform to get the NV state. The result state is saved internally
39 // and will be reported by NvIsAvailable(). The reference code requires that
40 // accessibility of NV does not change during the execution of a command.
41 // Specifically, if NV is available when the command execution starts and then
42 // is not available later when it is necessary to write to NV, then the TPM
43 // will go into failure mode.
44 NvCheckState();
45
46 // Due to the limitations of the simulation, TPM clock must be explicitly
47 // synchronized with the system clock whenever a command is received.
48 // This function call is not necessary in a hardware TPM. However, taking
49 // a snapshot of the hardware timer at the beginning of the command allows
50 // the time value to be consistent for the duration of the command execution.
51 TimeUpdateToCurrent();
52
53 // Any command through this function will unceremoniously end the
54 // _TPM_Hash_Data/_TPM_Hash_End sequence.
55 if(g_DRTMHandle != TPM_RH_UNASSIGNED)
56 ObjectTerminateEvent();
57
58 // Get command buffer size and command buffer.
59 command.parameterBuffer = request;
60 command.parameterSize = requestSize;
61
62 // Parse command header: tag, commandSize and command.code.
63 // First parse the tag. The unmarshaling routine will validate
64 // that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
65 result = TPMI_ST_COMMAND_TAG_Unmarshal(&command.tag,
66 &command.parameterBuffer,
67 &command.parameterSize);
68 if(result != TPM_RC_SUCCESS)
69 goto Cleanup;
70 // Unmarshal the commandSize indicator.
71 result = UINT32_Unmarshal(&commandSize,
72 &command.parameterBuffer,
73 &command.parameterSize);
74 if(result != TPM_RC_SUCCESS)
75 goto Cleanup;
76 // On a TPM that receives bytes on a port, the number of bytes that were
77 // received on that port is requestSize it must be identical to commandSize.
78 // In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
79 // by the implementation. The check against MAX_COMMAND_SIZE may be redundant
80 // as the input processing (the function that receives the command bytes and
81 // places them in the input buffer) would likely have the input truncated when
82 // it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
83 if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
84 {
85 result = TPM_RC_COMMAND_SIZE;
86 goto Cleanup;
87 }
88 // Unmarshal the command code.
89 result = TPM_CC_Unmarshal(&command.code, &command.parameterBuffer,
90 &command.parameterSize);
91 if(result != TPM_RC_SUCCESS)
92 goto Cleanup;
93 // Check to see if the command is implemented.
94 command.index = CommandCodeToCommandIndex(command.code);
95 if(UNIMPLEMENTED_COMMAND_INDEX == command.index)
96 {
97 result = TPM_RC_COMMAND_CODE;
98 goto Cleanup;
99 }
100 #if FIELD_UPGRADE_IMPLEMENTED == YES
101 // If the TPM is in FUM, then the only allowed command is
102 // TPM_CC_FieldUpgradeData.
103 if(IsFieldUgradeMode() && (command.code != TPM_CC_FieldUpgradeData))
104 {
105 result = TPM_RC_UPGRADE;
106 goto Cleanup;
107 }
108 else
109 #endif
110 // Excepting FUM, the TPM only accepts TPM2_Startup() after
111 // _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
112 // is no longer allowed.
113 if((!TPMIsStarted() && command.code != TPM_CC_Startup)
114 || (TPMIsStarted() && command.code == TPM_CC_Startup))
115 {
116 result = TPM_RC_INITIALIZE;
117 goto Cleanup;
118 }
119 // Start regular command process.
120 NvIndexCacheInit();
121 // Parse Handle buffer.
122 result = ParseHandleBuffer(&command);
123 if(result != TPM_RC_SUCCESS)
124 goto Cleanup;
125 // All handles in the handle area are required to reference TPM-resident
126 // entities.
127 result = EntityGetLoadStatus(&command);
128 if(result != TPM_RC_SUCCESS)
129 goto Cleanup;
130 // Authorization session handling for the command.
131 ClearCpRpHashes(&command);
132 if(command.tag == TPM_ST_SESSIONS)
133 {
134 // Find out session buffer size.
135 result = UINT32_Unmarshal((UINT32 *)&command.authSize,
136 &command.parameterBuffer,
137 &command.parameterSize);
138 if(result != TPM_RC_SUCCESS)
139 goto Cleanup;
140 // Perform sanity check on the unmarshaled value. If it is smaller than
141 // the smallest possible session or larger than the remaining size of
142 // the command, then it is an error. NOTE: This check could pass but the
143 // session size could still be wrong. That will be determined after the
144 // sessions are unmarshaled.
145 if(command.authSize < 9
146 || command.authSize > command.parameterSize)
147 {
148 result = TPM_RC_SIZE;
149 goto Cleanup;
150 }
151 command.parameterSize -= command.authSize;
152
153 // The actions of ParseSessionBuffer() are described in the introduction.
154 // As the sessions are parsed command.parameterBuffer is advanced so, on a
155 // successful return, command.parameterBuffer should be pointing at the
156 // first byte of the parameters.
157 result = ParseSessionBuffer(&command);
158 if(result != TPM_RC_SUCCESS)
159 goto Cleanup;
160 }
161 else
162 {
163 command.authSize = 0;
164 // The command has no authorization sessions.
165 // If the command requires authorizations, then CheckAuthNoSession() will
166 // return an error.
167 result = CheckAuthNoSession(&command);
168 if(result != TPM_RC_SUCCESS)
169 goto Cleanup;
170 }
171 // Set up the response buffer pointers. CommandDispatch will marshal the
172 // response parameters starting at the address in command.responseBuffer.
173 //*response = MemoryGetResponseBuffer(command.index);
174 // leave space for the command header
175 command.responseBuffer = *response + STD_RESPONSE_HEADER;
176
177 // leave space for the parameter size field if needed
178 if(command.tag == TPM_ST_SESSIONS)
179 command.responseBuffer += sizeof(UINT32);
180 if(IsHandleInResponse(command.index))
181 command.responseBuffer += sizeof(TPM_HANDLE);
182
183 // CommandDispatcher returns a response handle buffer and a response parameter
184 // buffer if it succeeds. It will also set the parameterSize field in the
185 // buffer if the tag is TPM_RC_SESSIONS.
186 result = CommandDispatcher(&command);
187 if(result != TPM_RC_SUCCESS)
188 goto Cleanup;
189
190 // Build the session area at the end of the parameter area.
191 BuildResponseSession(&command);
192
193 Cleanup:
194 if(g_clearOrderly == TRUE
195 && NV_IS_ORDERLY)
196 {
197 #if USE_DA_USED
198 gp.orderlyState = g_daUsed ? SU_DA_USED_VALUE : SU_NONE_VALUE;
199 #else
200 gp.orderlyState = SU_NONE_VALUE;
201 #endif
202 NV_SYNC_PERSISTENT(orderlyState);
203 }
204 // This implementation loads an "evict" object to a transient object slot in
205 // RAM whenever an "evict" object handle is used in a command so that the
206 // access to any object is the same. These temporary objects need to be
207 // cleared from RAM whether the command succeeds or fails.
208 ObjectCleanupEvict();
209
210 // The parameters and sessions have been marshaled. Now tack on the header and
211 // set the sizes
212 BuildResponseHeader(&command, *response, result);
213
214 // Try to commit all the writes to NV if any NV write happened during this
215 // command execution. This check should be made for both succeeded and failed
216 // commands, because a failed one may trigger a NV write in DA logic as well.
217 // This is the only place in the command execution path that may call the NV
218 // commit. If the NV commit fails, the TPM should be put in failure mode.
219 if((g_updateNV != UT_NONE) && !g_inFailureMode)
220 {
221 if(g_updateNV == UT_ORDERLY)
222 NvUpdateIndexOrderlyData();
223 if(!NvCommit())
224 FAIL(FATAL_ERROR_INTERNAL);
225 g_updateNV = UT_NONE;
226 }
227 pAssert((UINT32)command.parameterSize <= maxResponse);
228
229 // Clear unused bits in response buffer.
230 MemorySet(*response + *responseSize, 0, maxResponse - *responseSize);
231
232 // as a final act, and not before, update the response size.
233 *responseSize = (UINT32)command.parameterSize;
234
235 return;
236 }
6.3 CommandDispatcher.c
6.3.1 Introduction
NOTE 1 Unlike other unmarshaling functions, parmBufferStart does not advance. parmBufferSize Is reduced.
NOTE 2 The output buffer is the return from the MemoryGetResponseBuffer() function. It includes the header, handles,
response parameters, and authorization area. respParmSize is the response parameter size, and does not
include the header, handles, or authorization area.
NOTE 3 The reference implementation is permitted to do compare operations over a union as a byte array. Therefore,
the command parameter in structure must be initialized (e.g., zeroed) before unmarshaling so that the compare
operation is valid in cases where some bytes are unused.
1 #include "Tpm.h"
2 #include "Marshal.h"
3 #if TABLE_DRIVEN_DISPATCH
4 typedef TPM_RC(NoFlagFunction)(void *target, BYTE **buffer, INT32 *size);
5 typedef TPM_RC(FlagFunction)(void *target, BYTE **buffer, INT32 *size, BOOL flag);
6 typedef FlagFunction *UNMARSHAL_t;
7 typedef INT16(MarshalFunction)(void *source, BYTE **buffer, INT32 *size);
8 typedef MarshalFunction *MARSHAL_t;
9 typedef TPM_RC(COMMAND_NO_ARGS)(void);
10 typedef TPM_RC(COMMAND_IN_ARG)(void *in);
11 typedef TPM_RC(COMMAND_OUT_ARG)(void *out);
12 typedef TPM_RC(COMMAND_INOUT_ARG)(void *in, void *out);
13 typedef union COMMAND_t
14 {
15 COMMAND_NO_ARGS *noArgs;
16 COMMAND_IN_ARG *inArg;
17 COMMAND_OUT_ARG *outArg;
18 COMMAND_INOUT_ARG *inOutArg;
19 } COMMAND_t;
The types list is an encoded byte array. The byte value has two parts. The most significant bit is used
when a parameter takes a flag and indicates if the flag should be SET or not. The remaining 7 bits are an
index into an array of addresses of marshaling and unmarshaling functions. The array of functions is
divided into 6 sections with a value assigned to denote the start of that section (and the end of the
previous section). The defined offset values for each section are:
The types list is constructed with a byte of 0xff at the end of the command parameters and with an 0xff at
the end of the response parameters.
28 #if COMPRESSED_LISTS
29 # define PAD_LIST 0
30 #else
31 # define PAD_LIST 1
32 #endif
33 #define _COMMAND_TABLE_DISPATCH_
34 #include "CommandDispatchData.h"
35 #define TEST_COMMAND TPM_CC_Startup
36 #define NEW_CC
37 #else
38 #include "Commands.h"
39 #endif
6.3.1.2.1 ParseHandleBuffer()
40 TPM_RC
41 ParseHandleBuffer(
42 COMMAND *command
43 )
44 {
45 TPM_RC result;
46 #if TABLE_DRIVEN_DISPATCH
47 COMMAND_DESCRIPTOR_t *desc;
48 BYTE *types;
49 BYTE type;
50 BYTE dType;
51
52 // Make sure that nothing strange has happened
53 pAssert(command->index
54 < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t *));
55 // Get the address of the descriptor for this command
56 desc = s_CommandDataArray[command->index];
57
58 pAssert(desc != NULL);
59 // Get the associated list of unmarshaling data types.
60 types = &((BYTE *)desc)[desc->typesOffset];
61
62 // if(s_ccAttr[commandIndex].commandIndex == TEST_COMMAND)
63 // commandIndex = commandIndex;
64 // No handles yet
65 command->handleNum = 0;
66
6.3.1.2.2 CommandDispatcher()
Function to unmarshal the command parameters, call the selected action code, and marshal the
response parameters.
130 TPM_RC
131 CommandDispatcher(
132 COMMAND *command
133 )
134 {
135 #if !TABLE_DRIVEN_DISPATCH
136 TPM_RC result;
137 BYTE **paramBuffer = &command->parameterBuffer;
138 INT32 *paramBufferSize = &command->parameterSize;
139 BYTE **responseBuffer = &command->responseBuffer;
140 INT32 *respParmSize = &command->parameterSize;
141 INT32 rSize;
142 TPM_HANDLE *handles = &command->handles[0];
143 //
144 command->handleNum = 0; // The command-specific code knows how
145 // many handles there are. This is for
146 // cataloging the number of response
147 // handles
148 MemoryIoBufferAllocationReset(); // Initialize so that allocation will
149 // work properly
150 switch(GetCommandCode(command->index))
151 {
152 #include "CommandDispatcher.h"
153
154 default:
155 FAIL(FATAL_ERROR_INTERNAL);
156 break;
157 }
158 Exit:
159 MemoryIoBufferZero();
160 return result;
161 #else
162 COMMAND_DESCRIPTOR_t *desc;
163 BYTE *types;
164 BYTE type;
165 UINT16 *offsets;
166 UINT16 offset = 0;
167 UINT32 maxInSize;
168 BYTE *commandIn;
169 INT32 maxOutSize;
170 BYTE *commandOut;
171 COMMAND_t cmd;
172 TPM_HANDLE *handles;
173 UINT32 hasInParameters = 0;
174 BOOL hasOutParameters = FALSE;
175 UINT32 pNum = 0;
176 BYTE dType; // dispatch type
177 TPM_RC result;
178 //
179 // Get the address of the descriptor for this command
180 pAssert(command->index
181 < sizeof(s_CommandDataArray) / sizeof(COMMAND_DESCRIPTOR_t *));
182 desc = s_CommandDataArray[command->index];
183
184 // Get the list of parameter types for this command
185 pAssert(desc != NULL);
186 types = &((BYTE *)desc)[desc->typesOffset];
187
188 // Get a pointer to the list of parameter offsets
189 offsets = &desc->offsets[0];
6.4 SessionProcess.c
6.4.1 Introduction
This file contains the subsystem that process the authorization sessions including implementation of the
Dictionary Attack logic. ExecCommand() uses ParseSessionBuffer() to process the authorization session
area of a command and BuildResponseSession() to create the authorization session area of a response.
1 #define SESSION_PROCESS_C
2 #include "Tpm.h"
3 #include "ACT.h"
6.4.3.1 IsDAExempted()
4 BOOL
5 IsDAExempted(
6 TPM_HANDLE handle // IN: entity handle
7 )
8 {
9 BOOL result = FALSE;
10 //
11 switch(HandleGetType(handle))
12 {
13 case TPM_HT_PERMANENT:
14 // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
15 // DA protection.
16 result = (handle != TPM_RH_LOCKOUT);
17 break;
18 // When this function is called, a persistent object will have been loaded
19 // into an object slot and assigned a transient handle.
20 case TPM_HT_TRANSIENT:
21 {
22 TPMA_OBJECT attributes = ObjectGetPublicAttributes(handle);
23 result = IS_ATTRIBUTE(attributes, TPMA_OBJECT, noDA);
24 break;
25 }
26 case TPM_HT_NV_INDEX:
27 {
28 NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL);
29 result = IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, NO_DA);
30 break;
31 }
32 case TPM_HT_PCR:
33 // PCRs are always exempted from DA.
34 result = TRUE;
35 break;
36 default:
37 break;
38 }
39 return result;
40 }
6.4.3.2 IncrementLockout()
This function is called after an authorization failure that involves use of an authValue. If the entity
referenced by the handle is not exempt from DA protection, then the failedTries counter will be
incremented.
41 static TPM_RC
42 IncrementLockout(
43 UINT32 sessionIndex
44 )
45 {
46 TPM_HANDLE handle = s_associatedHandles[sessionIndex];
47 TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
48 SESSION *session = NULL;
49 //
50 // Don't increment lockout unless the handle associated with the session
51 // is DA protected or the session is bound to a DA protected entity.
52 if(sessionHandle == TPM_RS_PW)
53 {
54 if(IsDAExempted(handle))
55 return TPM_RC_BAD_AUTH;
56 }
57 else
58 {
59 session = SessionGet(sessionHandle);
60 // If the session is bound to lockout, then use that as the relevant
61 // handle. This means that an authorization failure with a bound session
62 // bound to lockoutAuth will take precedence over any other
63 // lockout check
64 if(session->attributes.isLockoutBound == SET)
65 handle = TPM_RH_LOCKOUT;
66 if(session->attributes.isDaBound == CLEAR
67 && (IsDAExempted(handle) || session->attributes.includeAuth == CLEAR))
68 // If the handle was changed to TPM_RH_LOCKOUT, this will not return
69 // TPM_RC_BAD_AUTH
70 return TPM_RC_BAD_AUTH;
71 }
72 if(handle == TPM_RH_LOCKOUT)
73 {
74 pAssert(gp.lockOutAuthEnabled == TRUE);
75
76 // lockout is no longer enabled
77 gp.lockOutAuthEnabled = FALSE;
78
79 // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
80 // the lockout authorization will be reset at startup.
81 if(gp.lockoutRecovery != 0)
82 {
83 if(NV_IS_AVAILABLE)
84 // Update NV.
85 NV_SYNC_PERSISTENT(lockOutAuthEnabled);
86 else
87 // No NV access for now. Put the TPM in pending mode.
88 s_DAPendingOnNV = TRUE;
89 }
90 }
91 else
92 {
93 if(gp.recoveryTime != 0)
94 {
95 gp.failedTries++;
96 if(NV_IS_AVAILABLE)
97 // Record changes to NV. NvWrite will SET g_updateNV
98 NV_SYNC_PERSISTENT(failedTries);
99 else
100 // No NV access for now. Put the TPM in pending mode.
101 s_DAPendingOnNV = TRUE;
102 }
103 }
104 // Register a DA failure and reset the timers.
105 DARegisterFailure(handle);
106
107 return TPM_RC_AUTH_FAIL;
108 }
6.4.3.3 IsSessionBindEntity()
This function indicates if the entity associated with the handle is the entity, to which this session is bound.
The binding would occur by making the bind parameter in TPM2_StartAuthSession() not equal to
TPM_RH_NULL. The binding only occurs if the session is an HMAC session. The bind value is a
combination of the Name and the authValue of the entity.
6.4.3.4 IsPolicySessionRequired()
Checks if a policy session is required for a command. If a command requires DUP or ADMIN role
authorization, then the handle that requires that role is the first handle in the command. This simplifies
this checking. If a new command is created that requires multiple ADMIN role authorizations, then it will
have to be special-cased in this function. A policy session is required if:
the command requires the DUP role,
the command requires the ADMIN role and the authorized entity is an object and its adminWithPolicy
bit is SET, or
the command requires the ADMIN role and the authorized entity is a permanent handle or an NV
Index.
The authorized entity is a PCR belonging to a policy group, and has its policy initialized
6.4.3.5 IsAuthValueAvailable()
This function indicates if authValue is available and allowed for USER role authorization of an entity.
This function is similar to IsAuthPolicyAvailable() except that it does not check the size of the authValue
as IsAuthPolicyAvailable() does (a null authValue is a valid authorization, but a null policy is not a valid
policy).
This function does not check that the handle reference is valid or if the entity is in an enabled hierarchy.
Those checks are assumed to have been performed during the handle unmarshaling.
6.4.3.6 IsAuthPolicyAvailable()
334 break;
335 }
336 break;
337 case TPM_HT_TRANSIENT:
338 {
339 // Object handle.
340 // An evict object would already have been loaded and given a
341 // transient object handle by this point.
342 OBJECT *object = HandleToObject(handle);
343 // Policy authorization is not available for an object with only
344 // public portion loaded.
345 if(object->attributes.publicOnly == CLEAR)
346 {
347 // Policy authorization is always available for an object but
348 // is never available for a sequence.
349 if(!ObjectIsSequence(object))
350 result = TRUE;
351 }
352 break;
353 }
354 case TPM_HT_NV_INDEX:
355 // An NV Index.
356 {
357 NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL);
358 TPMA_NV nvAttributes = nvIndex->publicArea.attributes;
359 //
360 // If the policy size is not zero, check if policy can be used.
361 if(nvIndex->publicArea.authPolicy.t.size != 0)
362 {
363 // If policy session is required for this handle, always
364 // uses policy regardless of the attributes bit setting
365 if(IsPolicySessionRequired(commandIndex, sessionIndex))
366 result = TRUE;
367 // Otherwise, the presence of the policy depends on the NV
368 // attributes.
369 else if(IsWriteOperation(commandIndex))
370 {
371 if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYWRITE))
372 result = TRUE;
373 }
374 else
375 {
376 if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYREAD))
377 result = TRUE;
378 }
379 }
380 }
381 break;
382 case TPM_HT_PCR:
383 // PCR handle.
384 if(PCRPolicyIsAvailable(handle))
385 result = TRUE;
386 break;
387 default:
388 break;
389 }
390 return result;
391 }
6.4.4.1 ClearCpRpHashes()
392 void
393 ClearCpRpHashes(
394 COMMAND *command
395 )
396 {
397 #if ALG_SHA1
398 command->sha1CpHash.t.size = 0;
399 command->sha1RpHash.t.size = 0;
400 #endif
401 #if ALG_SHA256
402 command->sha256CpHash.t.size = 0;
403 command->sha256RpHash.t.size = 0;
404 #endif
405 #if ALG_SHA384
406 command->sha384CpHash.t.size = 0;
407 command->sha384RpHash.t.size = 0;
408 #endif
409 #if ALG_SHA512
410 command->sha512CpHash.t.size = 0;
411 command->sha512RpHash.t.size = 0;
412 #endif
413 #if ALG_SM3_256
414 command->sm3_256CpHash.t.size = 0;
415 command->sm3_256RpHash.t.size = 0;
416 #endif
417 }
6.4.4.2 GetCpHashPointer()
452 #endif
453 default:
454 retVal = NULL;
455 break;
456 }
457 return retVal;
458 }
6.4.4.3 GetRpHashPointer()
6.4.4.4 ComputeCpHash()
This function computes the cpHash as defined in Part 2 and described in Part 1.
505 {
506 UINT32 i;
507 HASH_STATE hashState;
508 TPM2B_NAME name;
509 TPM2B_DIGEST *cpHash;
510 //
511 // cpHash = hash(commandCode [ || authName1
512 // [ || authName2
513 // [ || authName 3 ]]]
514 // [ || parameters])
515 // A cpHash can contain just a commandCode only if the lone session is
516 // an audit session.
517 // Get pointer to the hash value
518 cpHash = GetCpHashPointer(command, hashAlg);
519 if(cpHash->t.size == 0)
520 {
521 cpHash->t.size = CryptHashStart(&hashState, hashAlg);
522 // Add commandCode.
523 CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
524 // Add authNames for each of the handles.
525 for(i = 0; i < command->handleNum; i++)
526 CryptDigestUpdate2B(&hashState, &EntityGetName(command->handles[i],
527 &name)->b);
528 // Add the parameters.
529 CryptDigestUpdate(&hashState, command->parameterSize,
530 command->parameterBuffer);
531 // Complete the hash.
532 CryptHashEnd2B(&hashState, &cpHash->b);
533 }
534 return cpHash;
535 }
6.4.4.5 GetCpHash()
6.4.4.6 CompareTemplateHash()
This function computes the template hash and compares it to the session templateHash. It is the hash of
the second parameter assuming that the command is TPM2_Create(), TPM2_CreatePrimary(), or
TPM2_CreateLoaded()
6.4.4.7 CompareNameHash()
This function computes the name hash and compares it to the nameHash in the session data.
591 BOOL
592 CompareNameHash(
593 COMMAND *command, // IN: main parsing structure
594 SESSION *session // IN: session structure with nameHash
595 )
596 {
597 HASH_STATE hashState;
598 TPM2B_DIGEST nameHash;
599 UINT32 i;
600 TPM2B_NAME name;
601 //
602 nameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
603 // Add names.
604 for(i = 0; i < command->handleNum; i++)
605 CryptDigestUpdate2B(&hashState, &EntityGetName(command->handles[i],
606 &name)->b);
607 // Complete hash.
608 CryptHashEnd2B(&hashState, &nameHash.b);
6.4.4.8 CheckPWAuthSession()
This function validates the authorization provided in a PWAP session. It compares the input value to
authValue of the authorized entity. Argument sessionIndex is used to get handles handle of the
referenced entities from s_inputAuthValues[] and s_associatedHandles[].
6.4.4.9 ComputeCommandHMAC()
654 //
655 nonceDecrypt = NULL;
656 nonceEncrypt = NULL;
657
658 // Determine if extra nonceTPM values are going to be required.
659 // If this is the first session (sessionIndex = 0) and it is an authorization
660 // session that uses an HMAC, then check if additional session nonces are to be
661 // included.
662 if(sessionIndex == 0
663 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
664 {
665 // If there is a decrypt session and if this is not the decrypt session,
666 // then an extra nonce may be needed.
667 if(s_decryptSessionIndex != UNDEFINED_INDEX
668 && s_decryptSessionIndex != sessionIndex)
669 {
670 // Will add the nonce for the decrypt session.
671 SESSION *decryptSession
672 = SessionGet(s_sessionHandles[s_decryptSessionIndex]);
673 nonceDecrypt = &decryptSession->nonceTPM;
674 }
675 // Now repeat for the encrypt session.
676 if(s_encryptSessionIndex != UNDEFINED_INDEX
677 && s_encryptSessionIndex != sessionIndex
678 && s_encryptSessionIndex != s_decryptSessionIndex)
679 {
680 // Have to have the nonce for the encrypt session.
681 SESSION *encryptSession
682 = SessionGet(s_sessionHandles[s_encryptSessionIndex]);
683 nonceEncrypt = &encryptSession->nonceTPM;
684 }
685 }
686
687 // Continue with the HMAC processing.
688 session = SessionGet(s_sessionHandles[sessionIndex]);
689
690 // Generate HMAC key.
691 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
692
693 // Check if the session has an associated handle and if the associated entity
694 // is the one to which the session is bound. If not, add the authValue of
695 // this entity to the HMAC key.
696 // If the session is bound to the object or the session is a policy session
697 // with no authValue required, do not include the authValue in the HMAC key.
698 // Note: For a policy session, its isBound attribute is CLEARED.
699 //
700 // Include the entity authValue if it is needed
701 if(session->attributes.includeAuth == SET)
702 {
703 TPM2B_AUTH authValue;
704 // Get the entity authValue with trailing zeros removed
705 EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
706 // add the authValue to the HMAC key
707 MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
708 }
709 // if the HMAC key size is 0, a NULL string HMAC is allowed
710 if(key.t.size == 0
711 && s_inputAuthValues[sessionIndex].t.size == 0)
712 {
713 hmac->t.size = 0;
714 return hmac;
715 }
716 // Start HMAC
717 hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
718
719 // Add cpHash
720 CryptDigestUpdate2B(&hmacState.hashState,
721 &ComputeCpHash(command, session->authHashAlg)->b);
722 // Add nonces as required
723 CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
724 CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
725 if(nonceDecrypt != NULL)
726 CryptDigestUpdate2B(&hmacState.hashState, &nonceDecrypt->b);
727 if(nonceEncrypt != NULL)
728 CryptDigestUpdate2B(&hmacState.hashState, &nonceEncrypt->b);
729 // Add sessionAttributes
730 buffer = marshalBuffer;
731 marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]),
732 &buffer, NULL);
733 CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
734 // Complete the HMAC computation
735 CryptHmacEnd2B(&hmacState, &hmac->b);
736
737 return hmac;
738 }
6.4.4.10 CheckSessionHMAC()
This function checks the HMAC of in a session. It uses ComputeCommandHMAC() to compute the
expected HMAC value and then compares the result with the HMAC in the authorization session. The
authorization is successful if they are the same.
If the authorizations are not the same, IncrementLockout() is called. It will return TPM_RC_AUTH_FAIL if
the failure caused the failureCount to increment. Otherwise, it will return TPM_RC_BAD_AUTH.
6.4.4.11 CheckPolicyAuthSession()
This function is used to validate the authorization in a policy session. This function performs the following
comparisons to see if a policy authorization is properly provided. The check are:
compare policyDigest in session with authPolicy associated with the entity to be authorized;
compare timeout if applicable;
compare commandCode if applicable;
compare cpHash if applicable; and
see if PCR values have changed since computed.
If all the above checks succeed, the handle is authorized. The order of these comparisons is not
important because any failure will result in the same error code.
797 {
798 // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE
799 // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that
800 // a new nonce will be created just that, because TPM time can't advance
801 // we can't do time-based operations.
802 RETURN_IF_NV_IS_NOT_AVAILABLE;
803
804 if((session->timeout < g_time)
805 || (session->epoch != g_timeEpoch))
806 return TPM_RC_EXPIRED;
807 }
808 // If command code is provided it must match
809 if(session->commandCode != 0)
810 {
811 if(session->commandCode != command->code)
812 return TPM_RC_POLICY_CC;
813 }
814 else
815 {
816 // If command requires a DUP or ADMIN authorization, the session must have
817 // command code set.
818 AUTH_ROLE role = CommandAuthRole(command->index, sessionIndex);
819 if(role == AUTH_ADMIN || role == AUTH_DUP)
820 return TPM_RC_POLICY_FAIL;
821 }
822 // Check command locality.
823 {
824 BYTE sessionLocality[sizeof(TPMA_LOCALITY)];
825 BYTE *buffer = sessionLocality;
826
827 // Get existing locality setting in canonical form
828 sessionLocality[0] = 0;
829 TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
830
831 // See if the locality has been set
832 if(sessionLocality[0] != 0)
833 {
834 // If so, get the current locality
835 locality = _plat__LocalityGet();
836 if(locality < 5)
837 {
838 if(((sessionLocality[0] & (1 << locality)) == 0)
839 || sessionLocality[0] > 31)
840 return TPM_RC_LOCALITY;
841 }
842 else if(locality > 31)
843 {
844 if(sessionLocality[0] != locality)
845 return TPM_RC_LOCALITY;
846 }
847 else
848 {
849 // Could throw an assert here but a locality error is just
850 // as good. It just means that, whatever the locality is, it isn't
851 // the locality requested so...
852 return TPM_RC_LOCALITY;
853 }
854 }
855 } // end of locality check
856 // Check physical presence.
857 if(session->attributes.isPPRequired == SET
858 && !_plat__PhysicalPresenceAsserted())
859 return TPM_RC_PP;
860 // Compare cpHash/nameHash if defined, or if the command requires an ADMIN or
861 // DUP role for this handle.
862 if(session->u1.cpHash.b.size != 0)
863 {
864 BOOL OK;
865 if(session->attributes.isCpHashDefined)
866 // Compare cpHash.
867 OK = MemoryEqual2B(&session->u1.cpHash.b,
868 &ComputeCpHash(command, session->authHashAlg)->b);
869 else if(session->attributes.isTemplateSet)
870 OK = CompareTemplateHash(command, session);
871 else
872 OK = CompareNameHash(command, session);
873 if(!OK)
874 return TPM_RCS_POLICY_FAIL;
875 }
876 if(session->attributes.checkNvWritten)
877 {
878 NV_REF locator;
879 NV_INDEX *nvIndex;
880 //
881 // If this is not an NV index, the policy makes no sense so fail it.
882 if(HandleGetType(s_associatedHandles[sessionIndex]) != TPM_HT_NV_INDEX)
883 return TPM_RC_POLICY_FAIL;
884 // Get the index data
885 nvIndex = NvGetIndexInfo(s_associatedHandles[sessionIndex], &locator);
886
887 // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
888 if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
889 != (session->attributes.nvWrittenState == SET))
890 return TPM_RC_POLICY_FAIL;
891 }
892 return TPM_RC_SUCCESS;
893 }
6.4.4.12 RetrieveSessionData()
This function will unmarshal the sessions in the session area of a command. The values are placed in the
arrays that are defined at the beginning of this file. The normal unmarshaling errors are possible.
914
915 // If maximum allowed number of sessions has been parsed, return a size
916 // error with a session number that is larger than the number of allowed
917 // sessions
918 if(sessionIndex == MAX_SESSION_NUM)
919 return TPM_RCS_SIZE + errorIndex;
920 // make sure that the associated handle for each session starts out
921 // unassigned
922 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
923
924 // First parameter: Session handle.
925 result = TPMI_SH_AUTH_SESSION_Unmarshal(
926 &s_sessionHandles[sessionIndex],
927 &command->parameterBuffer,
928 &command->authSize, TRUE);
929 if(result != TPM_RC_SUCCESS)
930 return result + TPM_RC_S + g_rcIndex[sessionIndex];
931 // Second parameter: Nonce.
932 result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
933 &command->parameterBuffer,
934 &command->authSize);
935 if(result != TPM_RC_SUCCESS)
936 return result + TPM_RC_S + g_rcIndex[sessionIndex];
937 // Third parameter: sessionAttributes.
938 result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
939 &command->parameterBuffer,
940 &command->authSize);
941 if(result != TPM_RC_SUCCESS)
942 return result + TPM_RC_S + g_rcIndex[sessionIndex];
943 // Fourth parameter: authValue (PW or HMAC).
944 result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
945 &command->parameterBuffer,
946 &command->authSize);
947 if(result != TPM_RC_SUCCESS)
948 return result + errorIndex;
949
950 sessionAttributes = s_attributes[sessionIndex];
951 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
952 {
953 // A PWAP session needs additional processing.
954 // Can't have any attributes set other than continueSession bit
955 if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)
956 || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)
957 || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)
958 || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
959 || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset))
960 return TPM_RCS_ATTRIBUTES + errorIndex;
961 // The nonce size must be zero.
962 if(s_nonceCaller[sessionIndex].t.size != 0)
963 return TPM_RCS_NONCE + errorIndex;
964 continue;
965 }
966 // For not password sessions...
967 // Find out if the session is loaded.
968 if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
969 return TPM_RC_REFERENCE_S0 + sessionIndex;
970 sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
971 session = SessionGet(s_sessionHandles[sessionIndex]);
972
973 // Check if the session is an HMAC/policy session.
974 if((session->attributes.isPolicy == SET
975 && sessionType == TPM_HT_HMAC_SESSION)
976 || (session->attributes.isPolicy == CLEAR
977 && sessionType == TPM_HT_POLICY_SESSION))
978 return TPM_RCS_HANDLE + errorIndex;
979 // Check that this handle has not previously been used.
6.4.4.13 CheckLockedOut()
This function checks to see if the TPM is in lockout. This function should only be called if the entity being
checked is subject to DA protection. The TPM is in lockout if the NV is not available and a DA write is
pending. Otherwise the TPM is locked out if checking for lockoutAuth (lockoutAuthCheck == TRUE) and
use of lockoutAuth is disabled, or failedTries >= maxTries
1094 }
1095 #endif
1096 }
1097 return TPM_RC_SUCCESS;
1098 }
6.4.4.14 CheckAuthSession()
This function checks that the authorization session properly authorizes the use of the associated handle.
6.4.4.15 CheckCommandAudit()
This function is called before the command is processed if audit is enabled for the command. It will check
to see if the audit can be performed and will ensure that the cpHash is available for the audit.
6.4.4.16 ParseSessionBuffer()
This function is the entry function for command session processing. It iterates sessions in session area
and reports if the required authorization has been properly provided. It also processes audit session and
passes the information of encryption sessions to parameter encryption module.
1253 TPM_RC
1254 ParseSessionBuffer(
1255 COMMAND *command // IN: the structure that contains
1256 )
1257 {
1258 TPM_RC result;
1259 UINT32 i;
1260 INT32 size = 0;
1261 TPM2B_AUTH extraKey;
1262 UINT32 sessionIndex;
1263 TPM_RC errorIndex;
1264 SESSION *session = NULL;
1265 //
1266 // Check if a command allows any session in its session area.
1267 if(!IsSessionAllowed(command->index))
1268 return TPM_RC_AUTH_CONTEXT;
1269 // Default-initialization.
1270 command->sessionNum = 0;
1271
1272 result = RetrieveSessionData(command);
1273 if(result != TPM_RC_SUCCESS)
1274 return result;
1275 // There is no command in the TPM spec that has more handles than
1276 // MAX_SESSION_NUM.
1277 pAssert(command->handleNum <= MAX_SESSION_NUM);
1278
1279 // Associate the session with an authorization handle.
1280 for(i = 0; i < command->handleNum; i++)
1281 {
1282 if(CommandAuthRole(command->index, i) != AUTH_NONE)
1283 {
1284 // If the received session number is less than the number of handles
1285 // that requires authorization, an error should be returned.
1286 // Note: for all the TPM 2.0 commands, handles requiring
1287 // authorization come first in a command input and there are only ever
1288 // two values requiring authorization
1289 if(i > (command->sessionNum - 1))
1290 return TPM_RC_AUTH_MISSING;
1291 // Record the handle associated with the authorization session
1292 s_associatedHandles[i] = command->handles[i];
1293 }
1294 }
1295 // Consistency checks are done first to avoid authorization failure when the
1296 // command will not be executed anyway.
1297 for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++)
1298 {
1299 errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
1300 // PW session must be an authorization session
1301 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
1302 {
6.4.4.17 CheckAuthNoSession()
Function to process a command with no session associated. The function makes sure all the handles in
the command require no authorization.
1404 TPM_RC
1405 CheckAuthNoSession(
1406 COMMAND *command // IN: command parsing structure
1407 )
1408 {
1409 UINT32 i;
1410 TPM_RC result = TPM_RC_SUCCESS;
1411 //
1412 // Check if the command requires authorization
1413 for(i = 0; i < command->handleNum; i++)
1414 {
1415 if(CommandAuthRole(command->index, i) != AUTH_NONE)
1416 return TPM_RC_AUTH_MISSING;
1417 }
1418 #ifdef TPM_CC_GetCommandAuditDigest
1419 // Check if the command should be audited.
1420 if(CommandAuditIsRequired(command->index))
1421 {
1422 result = CheckCommandAudit(command);
6.4.5.1 Introduction
The following functions build the session area in a response and handle the audit sessions (if present).
6.4.5.2 ComputeRpHash()
Function to compute rpHash (Response Parameter Hash). The rpHash is only computed if there is an
HMAC authorization session and the return code is TPM_RC_SUCCESS.
6.4.5.3 InitAuditSession()
6.4.5.4 UpdateAuditDigest
6.4.5.5 Audit()
6.4.5.6 CommandAudit()
6.4.5.7 UpdateAuditSessionStatus()
1565
1566 // If a session is used for audit
1567 if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit))
1568 {
1569 // An audit session has been found
1570 auditSession = s_sessionHandles[i];
1571
1572 // If the session has not been an audit session yet, or
1573 // the auditSetting bits indicate a reset, initialize it and set
1574 // it to be the exclusive session
1575 if(session->attributes.isAudit == CLEAR
1576 || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset))
1577 {
1578 InitAuditSession(session);
1579 g_exclusiveAuditSession = auditSession;
1580 }
1581 else
1582 {
1583 // Check if the audit session is the current exclusive audit
1584 // session and, if not, clear previous exclusive audit session.
1585 if(g_exclusiveAuditSession != auditSession)
1586 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1587 }
1588 // Report audit session exclusivity.
1589 if(g_exclusiveAuditSession == auditSession)
1590 {
1591 SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
1592 }
1593 else
1594 {
1595 CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
1596 }
1597 // Extend audit log.
1598 Audit(command, session);
1599 }
1600 }
1601 // If no audit session is found in the command, and the command allows
1602 // a session then, clear the current exclusive
1603 // audit session.
1604 if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index))
1605 {
1606 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1607 }
1608 return;
1609 }
6.4.5.8 ComputeResponseHMAC()
6.4.5.9 UpdateInternalSession()
6.4.5.10 BuildSingleResponseAuth()
6.4.5.11 UpdateAllNonceTPM()
1733 }
6.4.5.12 BuildResponseSession()
Function to build Session buffer in a response. The authorization data is added to the end of command-
>responseBuffer. The size of the authorization area is accumulated in command->authSize. When this is
called, command->responseBuffer is pointing at the next location in the response buffer to be filled. This
is where the authorization sessions will go, if any. command->parameterSize is the number of bytes that
have been marshaled as parameters in the output buffer.
1734 void
1735 BuildResponseSession(
1736 COMMAND *command // IN: structure that has relevant command
1737 // information
1738 )
1739 {
1740 pAssert(command->authSize == 0);
1741
1742 // Reset the parameter buffer to point to the start of the parameters so that
1743 // there is a starting point for any rpHash that might be generated and so there
1744 // is a place where parameter encryption would start
1745 command->parameterBuffer = command->responseBuffer - command->parameterSize;
1746
1747 // Session nonces should be updated before parameter encryption
1748 if(command->tag == TPM_ST_SESSIONS)
1749 {
1750 UpdateAllNonceTPM(command);
1751
1752 // Encrypt first parameter if applicable. Parameter encryption should
1753 // happen after nonce update and before any rpHash is computed.
1754 // If the encrypt session is associated with a handle, the authValue of
1755 // this handle will be concatenated with sessionKey to generate
1756 // encryption key, no matter if the handle is the session bound entity
1757 // or not. The authValue is added to sessionKey only when the authValue
1758 // is available.
1759 if(s_encryptSessionIndex != UNDEFINED_INDEX)
1760 {
1761 UINT32 size;
1762 TPM2B_AUTH extraKey;
1763 //
1764 extraKey.b.size = 0;
1765 // If this is an authorization session, include the authValue in the
1766 // generation of the encryption key
1767 if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED)
1768 {
1769 EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
1770 &extraKey);
1771 }
1772 size = EncryptSize(command->index);
1773 CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
1774 &s_nonceCaller[s_encryptSessionIndex].b,
1775 (UINT16)size,
1776 &extraKey,
1777 command->parameterBuffer);
1778 }
1779 }
1780 // Audit sessions should be processed regardless of the tag because
1781 // a command with no session may cause a change of the exclusivity state.
1782 UpdateAuditSessionStatus(command);
1783 #if CC_GetCommandAuditDigest
1784 // Command Audit
1785 if(CommandAuditIsRequired(command->index))
1786 CommandAudit(command);
1787 #endif
6.4.5.13 SessionRemoveAssociationToHandle()
This function deals with the case where an entity associated with an authorization is deleted during
command processing. The primary use of this is to support UndefineSpaceSpecial().
1831 void
1832 SessionRemoveAssociationToHandle(
1833 TPM_HANDLE handle
1834 )
1835 {
1836 UINT32 i;
1837 //
1838 for(i = 0; i < MAX_SESSION_NUM; i++)
1839 {
1840 if(s_associatedHandles[i] == handle)
1841 {
1842 s_associatedHandles[i] = TPM_RH_NULL;
1843 }
1844 }
1845 }
7.1 Introduction
This clause contains support routines that are called by the command action code in TPM 2.0 Part 3. The
functions are grouped by the command group that is supported by the functions.
7.2.1 Includes
1 #include "Tpm.h"
2 #include "Attest_spt_fp.h"
7.2.2 Functions
7.2.2.1 FillInAttestInfo()
3 void
4 FillInAttestInfo(
5 TPMI_DH_OBJECT signHandle, // IN: handle of signing object
6 TPMT_SIG_SCHEME *scheme, // IN/OUT: scheme to be used for signing
7 TPM2B_DATA *data, // IN: qualifying data
8 TPMS_ATTEST *attest // OUT: attest structure
9 )
10 {
11 OBJECT *signObject = HandleToObject(signHandle);
12
13 // Magic number
14 attest->magic = TPM_GENERATED_VALUE;
15
16 if(signObject == NULL)
17 {
18 // The name for a null handle is TPM_RH_NULL
19 // This is defined because UINT32_TO_BYTE_ARRAY does a cast. If the
20 // size of the cast is smaller than a constant, the compiler warns
21 // about the truncation of a constant value.
22 TPM_HANDLE nullHandle = TPM_RH_NULL;
23 attest->qualifiedSigner.t.size = sizeof(TPM_HANDLE);
24 UINT32_TO_BYTE_ARRAY(nullHandle, attest->qualifiedSigner.t.name);
25 }
26 else
27 {
28 // Certifying object qualified name
29 // if the scheme is anonymous, this is an empty buffer
30 if(CryptIsSchemeAnonymous(scheme->scheme))
31 attest->qualifiedSigner.t.size = 0;
32 else
33 attest->qualifiedSigner = signObject->qualifiedName;
34 }
35 // current clock in plain text
36 TimeFillInfo(&attest->clockInfo);
37
38 // Firmware version in plain text
39 attest->firmwareVersion = ((UINT64)gp.firmwareV1 << (sizeof(UINT32) * 8));
40 attest->firmwareVersion += gp.firmwareV2;
41
42 // Check the hierarchy of sign object. For NULL sign handle, the hierarchy
43 // will be TPM_RH_NULL
44 if((signObject == NULL)
45 || (!signObject->attributes.epsHierarchy
46 && !signObject->attributes.ppsHierarchy))
47 {
48 // For signing key that is not in platform or endorsement hierarchy,
49 // obfuscate the reset, restart and firmware version information
50 UINT64 obfuscation[2];
51 CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gp.shProof.b, OBFUSCATE_STRING,
52 &attest->qualifiedSigner.b, NULL, 128,
53 (BYTE *)&obfuscation[0], NULL, FALSE);
54 // Obfuscate data
55 attest->firmwareVersion += obfuscation[0];
56 attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32);
57 attest->clockInfo.restartCount += (UINT32)obfuscation[1];
58 }
59 // External data
60 if(CryptIsSchemeAnonymous(scheme->scheme))
61 attest->extraData.t.size = 0;
62 else
63 {
64 // If we move the data to the attestation structure, then it is not
65 // used in the signing operation except as part of the signed data
66 attest->extraData = *data;
67 data->t.size = 0;
68 }
69 }
7.2.2.2 SignAttestInfo()
70 TPM_RC
71 SignAttestInfo(
72 OBJECT *signKey, // IN: sign object
73 TPMT_SIG_SCHEME *scheme, // IN: sign scheme
74 TPMS_ATTEST *certifyInfo, // IN: the data to be signed
75 TPM2B_DATA *qualifyingData, // IN: extra data for the signing
76 // process
77 TPM2B_ATTEST *attest, // OUT: marshaled attest blob to be
78 // signed
79 TPMT_SIGNATURE *signature // OUT: signature
80 )
81 {
82 BYTE *buffer;
83 HASH_STATE hashState;
84 TPM2B_DIGEST digest;
85 TPM_RC result;
86
87 // Marshal TPMS_ATTEST structure for hash
88 buffer = attest->t.attestationData;
89 attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, NULL);
90
91 if(signKey == NULL)
92 {
93 signature->sigAlg = TPM_ALG_NULL;
94 result = TPM_RC_SUCCESS;
95 }
96 else
97 {
98 TPMI_ALG_HASH hashAlg;
99 // Compute hash
100 hashAlg = scheme->details.any.hashAlg;
101 // need to set the receive buffer to get something put in it
102 digest.t.size = sizeof(digest.t.buffer);
103 digest.t.size = CryptHashBlock(hashAlg, attest->t.size,
104 attest->t.attestationData,
105 digest.t.size, digest.t.buffer);
106 // If there is qualifying data, need to rehash the data
107 // hash(qualifyingData || hash(attestationData))
108 if(qualifyingData->t.size != 0)
109 {
110 CryptHashStart(&hashState, hashAlg);
111 CryptDigestUpdate2B(&hashState, &qualifyingData->b);
112 CryptDigestUpdate2B(&hashState, &digest.b);
113 CryptHashEnd2B(&hashState, &digest.b);
114 }
115 // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or
116 // TPM_RC_ATTRIBUTES error may be returned at this point
117 result = CryptSign(signKey, scheme, &digest, signature);
118
119 // Since the clock is used in an attestation, the state in NV is no longer
120 // "orderly" with respect to the data in RAM if the signature is valid
121 if(result == TPM_RC_SUCCESS)
122 {
123 // Command uses the clock so need to clear the orderly state if it is
124 // set.
125 result = NvClearOrderly();
126 }
127 }
128 return result;
129 }
7.2.2.3 IsSigningObject()
Checks to see if the object is OK for signing. This is here rather than in Object_spt.c because all the
attestation commands use this file but not Object_spt.c.
130 BOOL
131 IsSigningObject(
132 OBJECT *object // IN:
133 )
134 {
135 return ((object == NULL)
136 || ((IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, sign)
137 && object->publicArea.type != TPM_ALG_SYMCIPHER)));
138 }
7.3.1 Includes
1 #include "Tpm.h"
2 #include "Context_spt_fp.h"
7.3.2 Functions
7.3.2.1 ComputeContextProtectionKey()
This function retrieves the symmetric protection key for context encryption It is used by
TPM2_ConextSave() and TPM2_ContextLoad() to create the symmetric encryption key and iv
3 void
4 ComputeContextProtectionKey(
5 TPMS_CONTEXT *contextBlob, // IN: context blob
6 TPM2B_SYM_KEY *symKey, // OUT: the symmetric key
7 TPM2B_IV *iv // OUT: the IV.
8 )
9 {
10 UINT16 symKeyBits; // number of bits in the parent's
11 // symmetric key
12 TPM2B_PROOF *proof = NULL; // the proof value to use. Is null for
13 // everything but a primary object in
14 // the Endorsement Hierarchy
15
16 BYTE kdfResult[sizeof(TPMU_HA) * 2];// Value produced by the KDF
17
18 TPM2B_DATA sequence2B, handle2B;
19
20 // Get proof value
21 proof = HierarchyGetProof(contextBlob->hierarchy);
22
23 // Get sequence value in 2B format
24 sequence2B.t.size = sizeof(contextBlob->sequence);
25 cAssert(sizeof(contextBlob->sequence) <= sizeof(sequence2B.t.buffer));
26 MemoryCopy(sequence2B.t.buffer, &contextBlob->sequence,
27 sizeof(contextBlob->sequence));
28
29 // Get handle value in 2B format
30 handle2B.t.size = sizeof(contextBlob->savedHandle);
31 cAssert(sizeof(contextBlob->savedHandle) <= sizeof(handle2B.t.buffer));
32 MemoryCopy(handle2B.t.buffer, &contextBlob->savedHandle,
33 sizeof(contextBlob->savedHandle));
34
35 // Get the symmetric encryption key size
36 symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
37 symKeyBits = CONTEXT_ENCRYPT_KEY_BITS;
38 // Get the size of the IV for the algorithm
39 iv->t.size = CryptGetSymmetricBlockSize(CONTEXT_ENCRYPT_ALG, symKeyBits);
40
41 // KDFa to generate symmetric key and IV value
42 CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &proof->b, CONTEXT_KEY, &sequence2B.b,
43 &handle2B.b, (symKey->t.size + iv->t.size) * 8, kdfResult, NULL,
44 FALSE);
45
46 // Copy part of the returned value as the key
47 pAssert(symKey->t.size <= sizeof(symKey->t.buffer));
48 MemoryCopy(symKey->t.buffer, kdfResult, symKey->t.size);
49
7.3.2.2 ComputeContextIntegrity()
Generate the integrity hash for a context It is used by TPM2_ContextSave() to create an integrity hash
and by TPM2_ContextLoad() to compare an integrity hash
56 void
57 ComputeContextIntegrity(
58 TPMS_CONTEXT *contextBlob, // IN: context blob
59 TPM2B_DIGEST *integrity // OUT: integrity
60 )
61 {
62 HMAC_STATE hmacState;
63 TPM2B_PROOF *proof;
64 UINT16 integritySize;
65
66 // Get proof value
67 proof = HierarchyGetProof(contextBlob->hierarchy);
68
69 // Start HMAC
70 integrity->t.size = CryptHmacStart2B(&hmacState, CONTEXT_INTEGRITY_HASH_ALG,
71 &proof->b);
72
73 // Compute integrity size at the beginning of context blob
74 integritySize = sizeof(integrity->t.size) + integrity->t.size;
75
76 // Adding total reset counter so that the context cannot be
77 // used after a TPM Reset
78 CryptDigestUpdateInt(&hmacState.hashState, sizeof(gp.totalResetCount),
79 gp.totalResetCount);
80
81 // If this is a ST_CLEAR object, add the clear count
82 // so that this contest cannot be loaded after a TPM Restart
83 if(contextBlob->savedHandle == 0x80000002)
84 CryptDigestUpdateInt(&hmacState.hashState, sizeof(gr.clearCount),
85 gr.clearCount);
86
87 // Adding sequence number to the HMAC to make sure that it doesn't
88 // get changed
89 CryptDigestUpdateInt(&hmacState.hashState, sizeof(contextBlob->sequence),
90 contextBlob->sequence);
91
92 // Protect the handle
93 CryptDigestUpdateInt(&hmacState.hashState, sizeof(contextBlob->savedHandle),
94 contextBlob->savedHandle);
95
96 // Adding sensitive contextData, skip the leading integrity area
97 CryptDigestUpdate(&hmacState.hashState,
98 contextBlob->contextBlob.t.size - integritySize,
99 contextBlob->contextBlob.t.buffer + integritySize);
100
101 // Complete HMAC
102 CryptHmacEnd2B(&hmacState, &integrity->b);
103
104 return;
105 }
7.3.2.3 SequenceDataExport()
This function is used scan through the sequence object and either modify the hash state data for export
(contextSave) or to import it into the internal format (contextLoad). This function should only be called
after the sequence object has been copied to the context buffer (contextSave) or from the context buffer
into the sequence object. The presumption is that the context buffer version of the data is the same size
as the internal representation so nothing outsize of the hash context area gets modified.
106 void
107 SequenceDataExport(
108 HASH_OBJECT *object, // IN: an internal hash object
109 HASH_OBJECT_BUFFER *exportObject // OUT: a sequence context in a buffer
110 )
111 {
112 // If the hash object is not an event, then only one hash context is needed
113 int count = (object->attributes.eventSeq) ? HASH_COUNT : 1;
114
115 for(count--; count >= 0; count--)
116 {
117 HASH_STATE *hash = &object->state.hashState[count];
118 size_t offset = (BYTE *)hash - (BYTE *)object;
119 BYTE *exportHash = &((BYTE *)exportObject)[offset];
120
121 CryptHashExportState(hash, (EXPORT_HASH_STATE *)exportHash);
122 }
123 }
7.3.2.4 SequenceDataImport()
This function is used scan through the sequence object and either modify the hash state data for export
(contextSave) or to import it into the internal format (contextLoad). This function should only be called
after the sequence object has been copied to the context buffer (contextSave) or from the context buffer
into the sequence object. The presumption is that the context buffer version of the data is the same size
as the internal representation so nothing outsize of the hash context area gets modified.
124 void
125 SequenceDataImport(
126 HASH_OBJECT *object, // IN/OUT: an internal hash object
127 HASH_OBJECT_BUFFER *exportObject // IN/OUT: a sequence context in a buffer
128 )
129 {
130 // If the hash object is not an event, then only one hash context is needed
131 int count = (object->attributes.eventSeq) ? HASH_COUNT : 1;
132
133 for(count--; count >= 0; count--)
134 {
135 HASH_STATE *hash = &object->state.hashState[count];
136 size_t offset = (BYTE *)hash - (BYTE *)object;
137 BYTE *importHash = &((BYTE *)exportObject)[offset];
138 //
139 CryptHashImportState(hash, (EXPORT_HASH_STATE *)importHash);
140 }
141 }
7.4.1 Includes
1 #include "Tpm.h"
2 #include "Policy_spt_fp.h"
3 #include "PolicySigned_fp.h"
4 #include "PolicySecret_fp.h"
5 #include "PolicyTicket_fp.h"
7.4.2 Functions
7.4.2.1 PolicyParameterChecks()
This function validates the common parameters of TPM2_PolicySiged() and TPM2_PolicySecret(). The
common parameters are nonceTPM, expiration, and cpHashA.
6 TPM_RC
7 PolicyParameterChecks(
8 SESSION *session,
9 UINT64 authTimeout,
10 TPM2B_DIGEST *cpHashA,
11 TPM2B_NONCE *nonce,
12 TPM_RC blameNonce,
13 TPM_RC blameCpHash,
14 TPM_RC blameExpiration
15 )
16 {
17 // Validate that input nonceTPM is correct if present
18 if(nonce != NULL && nonce->t.size != 0)
19 {
20 if(!MemoryEqual2B(&nonce->b, &session->nonceTPM.b))
21 return TPM_RCS_NONCE + blameNonce;
22 }
23 // If authTimeout is set (expiration != 0...
24 if(authTimeout != 0)
25 {
26 // Validate input expiration.
27 // Cannot compare time if clock stop advancing. A TPM_RC_NV_UNAVAILABLE
28 // or TPM_RC_NV_RATE error may be returned here.
29 RETURN_IF_NV_IS_NOT_AVAILABLE;
30
31 // if the time has already passed or the time epoch has changed then the
32 // time value is no longer good.
33 if((authTimeout < g_time)
34 || (session->epoch != g_timeEpoch))
35 return TPM_RCS_EXPIRED + blameExpiration;
36 }
37 // If the cpHash is present, then check it
38 if(cpHashA != NULL && cpHashA->t.size != 0)
39 {
40 // The cpHash input has to have the correct size
41 if(cpHashA->t.size != session->u2.policyDigest.t.size)
42 return TPM_RCS_SIZE + blameCpHash;
43
44 // If the cpHash has already been set, then this input value
45 // must match the current value.
46 if(session->u1.cpHash.b.size != 0
47 && !MemoryEqual2B(&cpHashA->b, &session->u1.cpHash.b))
48 return TPM_RC_CPHASH;
49 }
50 return TPM_RC_SUCCESS;
51 }
7.4.2.2 PolicyContextUpdate()
Update policy hash Update the policyDigest in policy session by extending policyRef and objectName to
it. This will also update the cpHash if it is present.
52 void
53 PolicyContextUpdate(
54 TPM_CC commandCode, // IN: command code
55 TPM2B_NAME *name, // IN: name of entity
56 TPM2B_NONCE *ref, // IN: the reference data
57 TPM2B_DIGEST *cpHash, // IN: the cpHash (optional)
58 UINT64 policyTimeout, // IN: the timeout value for the policy
59 SESSION *session // IN/OUT: policy session to be updated
60 )
61 {
62 HASH_STATE hashState;
63
64 // Start hash
65 CryptHashStart(&hashState, session->authHashAlg);
66
67 // policyDigest size should always be the digest size of session hash algorithm.
68 pAssert(session->u2.policyDigest.t.size
69 == CryptHashGetDigestSize(session->authHashAlg));
70
71 // add old digest
72 CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);
73
74 // add commandCode
75 CryptDigestUpdateInt(&hashState, sizeof(commandCode), commandCode);
76
77 // add name if applicable
78 if(name != NULL)
79 CryptDigestUpdate2B(&hashState, &name->b);
80
81 // Complete the digest and get the results
82 CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);
83
84 // If the policy reference is not null, do a second update to the digest.
85 if(ref != NULL)
86 {
87
88 // Start second hash computation
89 CryptHashStart(&hashState, session->authHashAlg);
90
91 // add policyDigest
92 CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);
93
94 // add policyRef
95 CryptDigestUpdate2B(&hashState, &ref->b);
96
97 // Complete second digest
98 CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);
99 }
100 // Deal with the cpHash. If the cpHash value is present
101 // then it would have already been checked to make sure that
102 // it is compatible with the current value so all we need
103 // to do here is copy it and set the isCpHashDefined attribute
104 if(cpHash != NULL && cpHash->t.size != 0)
105 {
106 session->u1.cpHash = *cpHash;
107 session->attributes.isCpHashDefined = SET;
108 }
109
110 // update the timeout if it is specified
111 if(policyTimeout != 0)
112 {
113 // If the timeout has not been set, then set it to the new value
114 // than the current timeout then set it to the new value
115 if(session->timeout == 0 || session->timeout > policyTimeout)
116 session->timeout = policyTimeout;
117 }
118 return;
119 }
7.4.2.3 ComputeAuthTimeout()
This function is used to determine what the authorization timeout value for the session should be.
120 UINT64
121 ComputeAuthTimeout(
122 SESSION *session, // IN: the session containing the time
123 // values
124 INT32 expiration, // IN: either the number of seconds from
125 // the start of the session or the
126 // time in g_timer;
127 TPM2B_NONCE *nonce // IN: indicator of the time base
128 )
129 {
130 UINT64 policyTime;
131 // If no expiration, policy time is 0
132 if(expiration == 0)
133 policyTime = 0;
134 else
135 {
136 if(expiration < 0)
137 expiration = -expiration;
138 if(nonce->t.size == 0)
139 // The input time is absolute Time (not Clock), but it is expressed
140 // in seconds. To make sure that we don't time out too early, take the
141 // current value of milliseconds in g_time and add that to the input
142 // seconds value.
143 policyTime = (((UINT64)expiration) * 1000) + g_time % 1000;
144 else
145 // The policy timeout is the absolute value of the expiration in seconds
146 // added to the start time of the policy.
147 policyTime = session->startTime + (((UINT64)expiration) * 1000);
148
149 }
150 return policyTime;
151 }
7.4.2.4 PolicyDigestClear()
152 void
153 PolicyDigestClear(
154 SESSION *session
155 )
156 {
157 session->u2.policyDigest.t.size = CryptHashGetDigestSize(session->authHashAlg);
158 MemorySet(session->u2.policyDigest.t.buffer, 0,
159 session->u2.policyDigest.t.size);
160 }
161 BOOL
162 PolicySptCheckCondition(
163 TPM_EO operation,
164 BYTE *opA,
165 BYTE *opB,
166 UINT16 size
167 )
168 {
169 // Arithmetic Comparison
170 switch(operation)
171 {
172 case TPM_EO_EQ:
173 // compare A = B
174 return (UnsignedCompareB(size, opA, size, opB) == 0);
175 break;
176 case TPM_EO_NEQ:
177 // compare A != B
178 return (UnsignedCompareB(size, opA, size, opB) != 0);
179 break;
180 case TPM_EO_SIGNED_GT:
181 // compare A > B signed
182 return (SignedCompareB(size, opA, size, opB) > 0);
183 break;
184 case TPM_EO_UNSIGNED_GT:
185 // compare A > B unsigned
186 return (UnsignedCompareB(size, opA, size, opB) > 0);
187 break;
188 case TPM_EO_SIGNED_LT:
189 // compare A < B signed
190 return (SignedCompareB(size, opA, size, opB) < 0);
191 break;
192 case TPM_EO_UNSIGNED_LT:
193 // compare A < B unsigned
194 return (UnsignedCompareB(size, opA, size, opB) < 0);
195 break;
196 case TPM_EO_SIGNED_GE:
197 // compare A >= B signed
198 return (SignedCompareB(size, opA, size, opB) >= 0);
199 break;
200 case TPM_EO_UNSIGNED_GE:
201 // compare A >= B unsigned
202 return (UnsignedCompareB(size, opA, size, opB) >= 0);
203 break;
204 case TPM_EO_SIGNED_LE:
205 // compare A <= B signed
206 return (SignedCompareB(size, opA, size, opB) <= 0);
207 break;
208 case TPM_EO_UNSIGNED_LE:
209 // compare A <= B unsigned
210 return (UnsignedCompareB(size, opA, size, opB) <= 0);
211 break;
212 case TPM_EO_BITSET:
213 // All bits SET in B are SET in A. ((A&B)=B)
214 {
215 UINT32 i;
216 for(i = 0; i < size; i++)
217 if((opA[i] & opB[i]) != opB[i])
218 return FALSE;
219 }
220 break;
221 case TPM_EO_BITCLEAR:
222 // All bits SET in B are CLEAR in A. ((A&B)=0)
223 {
224 UINT32 i;
225 for(i = 0; i < size; i++)
226 if((opA[i] & opB[i]) != 0)
7.5.1 Includes
1 #include "Tpm.h"
2 #include "NV_spt_fp.h"
7.5.2 Functions
7.5.2.1 NvReadAccessChecks()
3 TPM_RC
4 NvReadAccessChecks(
5 TPM_HANDLE authHandle, // IN: the handle that provided the
6 // authorization
7 TPM_HANDLE nvHandle, // IN: the handle of the NV index to be read
8 TPMA_NV attributes // IN: the attributes of 'nvHandle'
9 )
10 {
11 // If data is read locked, returns an error
12 if(IS_ATTRIBUTE(attributes, TPMA_NV, READLOCKED))
13 return TPM_RC_NV_LOCKED;
14 // If the authorization was provided by the owner or platform, then check
15 // that the attributes allow the read. If the authorization handle
16 // is the same as the index, then the checks were made when the authorization
17 // was checked..
18 if(authHandle == TPM_RH_OWNER)
19 {
20 // If Owner provided authorization then ONWERWRITE must be SET
21 if(!IS_ATTRIBUTE(attributes, TPMA_NV, OWNERREAD))
22 return TPM_RC_NV_AUTHORIZATION;
23 }
24 else if(authHandle == TPM_RH_PLATFORM)
25 {
26 // If Platform provided authorization then PPWRITE must be SET
27 if(!IS_ATTRIBUTE(attributes, TPMA_NV, PPREAD))
28 return TPM_RC_NV_AUTHORIZATION;
29 }
30 // If neither Owner nor Platform provided authorization, make sure that it was
31 // provided by this index.
32 else if(authHandle != nvHandle)
33 return TPM_RC_NV_AUTHORIZATION;
34
35 // If the index has not been written, then the value cannot be read
36 // NOTE: This has to come after other access checks to make sure that
37 // the proper authorization is given to TPM2_NV_ReadLock()
38 if(!IS_ATTRIBUTE(attributes, TPMA_NV, WRITTEN))
39 return TPM_RC_NV_UNINITIALIZED;
40
41 return TPM_RC_SUCCESS;
42 }
7.5.2.2 NvWriteAccessChecks()
43 TPM_RC
44 NvWriteAccessChecks(
45 TPM_HANDLE authHandle, // IN: the handle that provided the
46 // authorization
47 TPM_HANDLE nvHandle, // IN: the handle of the NV index to be written
48 TPMA_NV attributes // IN: the attributes of 'nvHandle'
49 )
50 {
51 // If data is write locked, returns an error
52 if(IS_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED))
53 return TPM_RC_NV_LOCKED;
54 // If the authorization was provided by the owner or platform, then check
55 // that the attributes allow the write. If the authorization handle
56 // is the same as the index, then the checks were made when the authorization
57 // was checked..
58 if(authHandle == TPM_RH_OWNER)
59 {
60 // If Owner provided authorization then ONWERWRITE must be SET
61 if(!IS_ATTRIBUTE(attributes, TPMA_NV, OWNERWRITE))
62 return TPM_RC_NV_AUTHORIZATION;
63 }
64 else if(authHandle == TPM_RH_PLATFORM)
65 {
66 // If Platform provided authorization then PPWRITE must be SET
67 if(!IS_ATTRIBUTE(attributes, TPMA_NV, PPWRITE))
68 return TPM_RC_NV_AUTHORIZATION;
69 }
70 // If neither Owner nor Platform provided authorization, make sure that it was
71 // provided by this index.
72 else if(authHandle != nvHandle)
73 return TPM_RC_NV_AUTHORIZATION;
74 return TPM_RC_SUCCESS;
75 }
7.5.2.3 NvClearOrderly()
76 TPM_RC
77 NvClearOrderly(
78 void
79 )
80 {
81 if(gp.orderlyState < SU_DA_USED_VALUE)
82 RETURN_IF_NV_IS_NOT_AVAILABLE;
83 g_clearOrderly = TRUE;
84 return TPM_RC_SUCCESS;
85 }
7.5.2.4 NvIsPinPassIndex()
86 BOOL
87 NvIsPinPassIndex(
88 TPM_HANDLE index // IN: Handle to check
89 )
90 {
91 if(HandleGetType(index) == TPM_HT_NV_INDEX)
92 {
93 NV_INDEX *nvIndex = NvGetIndexInfo(index, NULL);
94
95 return IsNvPinPassIndex(nvIndex->publicArea.attributes);
96 }
97 return FALSE;
98 }
7.6.1 Includes
1 #include "Tpm.h"
2 #include "Object_spt_fp.h"
7.6.2.1 GetIV2BSize()
Get the size of TPM2B_IV in canonical form that will be append to the start of the sensitive data. It
includes both size of size field and size of iv data
3 static UINT16
4 GetIV2BSize(
5 OBJECT *protector // IN: the protector handle
6 )
7 {
8 TPM_ALG_ID symAlg;
9 UINT16 keyBits;
10
11 // Determine the symmetric algorithm and size of key
12 if(protector == NULL)
13 {
14 // Use the context encryption algorithm and key size
15 symAlg = CONTEXT_ENCRYPT_ALG;
16 keyBits = CONTEXT_ENCRYPT_KEY_BITS;
17 }
18 else
19 {
20 symAlg = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
21 keyBits = protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
22 }
23
24 // The IV size is a UINT16 size field plus the block size of the symmetric
25 // algorithm
26 return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
27 }
7.6.2.2 ComputeProtectionKeyParms()
This function retrieves the symmetric protection key parameters for the sensitive data The parameters
retrieved from this function include encryption algorithm, key size in bit, and a TPM2B_SYM_KEY
containing the key material as well as the key size in bytes This function is used for any action that
requires encrypting or decrypting of the sensitive area of an object or a credential blob
28 static void
29 ComputeProtectionKeyParms(
30 OBJECT *protector, // IN: the protector object
31 TPM_ALG_ID hashAlg, // IN: hash algorithm for KDFa
32 TPM2B *name, // IN: name of the object
33 TPM2B *seedIn, // IN: optional seed for duplication blob.
34 // For non duplication blob, this
35 // parameter should be NULL
36 TPM_ALG_ID *symAlg, // OUT: the symmetric algorithm
37 UINT16 *keyBits, // OUT: the symmetric key size in bits
38 TPM2B_SYM_KEY *symKey // OUT: the symmetric key
39 )
40 {
41 const TPM2B *seed = seedIn;
42
43 // Determine the algorithms for the KDF and the encryption/decryption
44 // For TPM_RH_NULL, using context settings
45 if(protector == NULL)
46 {
47 // Use the context encryption algorithm and key size
48 *symAlg = CONTEXT_ENCRYPT_ALG;
49 symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
50 *keyBits = CONTEXT_ENCRYPT_KEY_BITS;
51 }
52 else
53 {
54 TPMT_SYM_DEF_OBJECT *symDef;
55 symDef = &protector->publicArea.parameters.asymDetail.symmetric;
56 *symAlg = symDef->algorithm;
57 *keyBits = symDef->keyBits.sym;
58 symKey->t.size = (*keyBits + 7) / 8;
59 }
60 // Get seed for KDF
61 if(seed == NULL)
62 seed = GetSeedForKDF(protector);
63 // KDFa to generate symmetric key and IV value
64 CryptKDFa(hashAlg, seed, STORAGE_KEY, name, NULL,
65 symKey->t.size * 8, symKey->t.buffer, NULL, FALSE);
66 return;
67 }
7.6.2.3 ComputeOuterIntegrity()
The sensitive area parameter is a buffer that holds a space for the integrity value and the marshaled
sensitive area. The caller should skip over the area set aside for the integrity value and compute the hash
of the remainder of the object. The size field of sensitive is in unmarshaled form and the sensitive area
contents is an array of bytes.
68 static void
69 ComputeOuterIntegrity(
70 TPM2B *name, // IN: the name of the object
71 OBJECT *protector, // IN: the object that
72 // provides protection. For an object,
73 // it is a parent. For a credential, it
74 // is the encrypt object. For
75 // a Temporary Object, it is NULL
76 TPMI_ALG_HASH hashAlg, // IN: algorithm to use for integrity
77 TPM2B *seedIn, // IN: an external seed may be provided for
78 // duplication blob. For non duplication
79 // blob, this parameter should be NULL
80 UINT32 sensitiveSize, // IN: size of the marshaled sensitive data
81 BYTE *sensitiveData, // IN: sensitive area
82 TPM2B_DIGEST *integrity // OUT: integrity
83 )
84 {
85 HMAC_STATE hmacState;
86 TPM2B_DIGEST hmacKey;
87 const TPM2B *seed = seedIn;
88 //
89 // Get seed for KDF
90 if(seed == NULL)
91 seed = GetSeedForKDF(protector);
92 // Determine the HMAC key bits
93 hmacKey.t.size = CryptHashGetDigestSize(hashAlg);
94
95 // KDFa to generate HMAC key
7.6.2.4 ComputeInnerIntegrity()
7.6.2.5 ProduceInnerIntegrity()
This function produces an inner integrity for regular private, credential or duplication blob It requires the
sensitive data being marshaled to the innerBuffer, with the leading bytes reserved for integrity hash. It
assume the sensitive data starts at address (innerBuffer + integrity size). This function integrity at the
beginning of the inner buffer It returns the total size of buffer with the inner wrap
7.6.2.6 CheckInnerIntegrity()
7.6.3.1 AdjustAuthSize()
This function will validate that the input authValue is no larger than the digestSize for the nameAlg. It will
then pad with zeros to the size of the digest.
196 BOOL
197 AdjustAuthSize(
198 TPM2B_AUTH *auth, // IN/OUT: value to adjust
199 TPMI_ALG_HASH nameAlg // IN:
200 )
201 {
202 UINT16 digestSize;
203 //
204 // If there is no nameAlg, then this is a LoadExternal and the authVale can
205 // be any size up to the maximum allowed by the
206 digestSize = (nameAlg == TPM_ALG_NULL) ? sizeof(TPMU_HA)
207 : CryptHashGetDigestSize(nameAlg);
208 if(digestSize < MemoryRemoveTrailingZeros(auth))
209 return FALSE;
210 else if(digestSize > auth->t.size)
211 MemoryPad2B(&auth->b, digestSize);
212 auth->t.size = digestSize;
213
214 return TRUE;
215 }
7.6.3.2 AreAttributesForParent()
NOTE: The isParent attribute is SET when an object is loaded and it has attributes that are suitable for a parent object.
216 BOOL
217 ObjectIsParent(
218 OBJECT *parentObject // IN: parent handle
219 )
220 {
221 return parentObject->attributes.isParent;
222 }
7.6.3.3 CreateChecks()
223 TPM_RC
224 CreateChecks(
7.6.3.4 SchemeChecks
277 TPM_RC
278 SchemeChecks(
279 OBJECT *parentObject, // IN: parent (null if primary seed)
280 TPMT_PUBLIC *publicArea // IN: public area of the object
281 )
282 {
283 TPMT_SYM_DEF_OBJECT *symAlgs = NULL;
284 TPM_ALG_ID scheme = TPM_ALG_NULL;
285 TPMA_OBJECT attributes = publicArea->objectAttributes;
286 TPMU_PUBLIC_PARMS *parms = &publicArea->parameters;
287 //
288 switch(publicArea->type)
289 {
290 case ALG_SYMCIPHER_VALUE:
291 symAlgs = &parms->symDetail.sym;
292 // If this is a decrypt key, then only the block cipher modes (not
293 // SMAC) are valid. TPM_ALG_NULL is OK too. If this is a 'sign' key,
294 // then any mode that got through the unmarshaling is OK.
295 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
296 && !CryptSymModeIsValid(symAlgs->mode.sym, TRUE))
297 return TPM_RCS_SCHEME;
298 break;
299 case ALG_KEYEDHASH_VALUE:
300 scheme = parms->keyedHashDetail.scheme.scheme;
301 // if both sign and decrypt
302 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
303 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
304 {
305 // if both sign and decrypt are set or clear, then need
306 // TPM_ALG_NULL as scheme
307 if(scheme != TPM_ALG_NULL)
308 return TPM_RCS_SCHEME;
309 }
310 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
311 && scheme != TPM_ALG_HMAC)
312 return TPM_RCS_SCHEME;
313 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
314 {
315 if(scheme != TPM_ALG_XOR)
316 return TPM_RCS_SCHEME;
317 // If this is a derivation parent, then the KDF needs to be
318 // SP800-108 for this implementation. This is the only derivation
319 // supported by this implementation. Other implementations could
320 // support additional schemes. There is no default.
321 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
322 {
323 if(parms->keyedHashDetail.scheme.details.xor.kdf
324 != TPM_ALG_KDF1_SP800_108)
325 return TPM_RCS_SCHEME;
326 // Must select a digest.
327 if(CryptHashGetDigestSize(
328 parms->keyedHashDetail.scheme.details.xor.hashAlg) == 0)
329 return TPM_RCS_HASH;
330 }
331 }
332 break;
333 default: // handling for asymmetric
334 scheme = parms->asymDetail.scheme.scheme;
335 symAlgs = &parms->asymDetail.symmetric;
336 // if the key is both sign and decrypt, then the scheme must be
337 // TPM_ALG_NULL because there is no way to specify both a sign and a
338 // decrypt scheme in the key.
339 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
340 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
341 {
342 // scheme must be TPM_ALG_NULL
343 if(scheme != TPM_ALG_NULL)
344 return TPM_RCS_SCHEME;
345 }
346 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
347 {
348 // If this is a signing key, see if it has a signing scheme
349 if(CryptIsAsymSignScheme(publicArea->type, scheme))
350 {
351 // if proper signing scheme then it needs a proper hash
352 if(parms->asymDetail.scheme.details.anySig.hashAlg
353 == TPM_ALG_NULL)
354 return TPM_RCS_SCHEME;
355 }
356 else
357 {
358 // signing key that does not have a proper signing scheme.
359 // This is OK if the key is not restricted and its scheme
360 // is TPM_ALG_NULL
361 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
362 || scheme != TPM_ALG_NULL)
363 return TPM_RCS_SCHEME;
364 }
365 }
366 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
367 {
368 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
369 {
370 // for a restricted decryption key (a parent), scheme
371 // is required to be TPM_ALG_NULL
372 if(scheme != TPM_ALG_NULL)
373 return TPM_RCS_SCHEME;
374 }
375 else
376 {
377 // For an unrestricted decryption key, the scheme has to
378 // be a valid scheme or TPM_ALG_NULL
379 if(scheme != TPM_ALG_NULL &&
380 !CryptIsAsymDecryptScheme(publicArea->type, scheme))
381 return TPM_RCS_SCHEME;
382 }
383 }
384 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
385 || !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
386 {
387 // For an asymmetric key that is not a parent, the symmetric
388 // algorithms must be TPM_ALG_NULL
389 if(symAlgs->algorithm != TPM_ALG_NULL)
390 return TPM_RCS_SYMMETRIC;
391 }
392 // Special checks for an ECC key
7.6.3.5 PublicAttributesValidation()
This function validates the values in the public area of an object. This function is used in the processing of
TPM2_Create(), TPM2_CreatePrimary(), TPM2_CreateLoaded(), TPM2_Load(), TPM2_Import(), and
TPM2_LoadExternal(). For TPM2_Import() this is only used if the new parent has fixedTPM SET. For
TPM2_LoadExternal(), this is not used for a public-only key
454 TPM_RC
455 PublicAttributesValidation(
456 OBJECT *parentObject, // IN: input parent object
457 TPMT_PUBLIC *publicArea // IN: public area of the object
458 )
459 {
460 TPMA_OBJECT attributes = publicArea->objectAttributes;
461 TPMA_OBJECT parentAttributes = TPMA_ZERO_INITIALIZER();
462 //
463 if(parentObject != NULL)
464 parentAttributes = parentObject->publicArea.objectAttributes;
465 if(publicArea->nameAlg == TPM_ALG_NULL)
466 return TPM_RCS_HASH;
467 // If there is an authPolicy, it needs to be the size of the digest produced
468 // by the nameAlg of the object
469 if((publicArea->authPolicy.t.size != 0
470 && (publicArea->authPolicy.t.size
471 != CryptHashGetDigestSize(publicArea->nameAlg))))
472 return TPM_RCS_SIZE;
473 // If the parent is fixedTPM (including a Primary Object) the object must have
474 // the same value for fixedTPM and fixedParent
475 if(parentObject == NULL
476 || IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
477 {
478 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
479 != IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
480 return TPM_RCS_ATTRIBUTES;
481 }
482 else
483 {
484 // The parent is not fixedTPM so the object can't be fixedTPM
485 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
486 return TPM_RCS_ATTRIBUTES;
487 }
488 // See if sign and decrypt are the same
489 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
490 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
491 {
492 // a restricted key cannot have both SET or both CLEAR
493 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
494 return TPM_RC_ATTRIBUTES;
495 // only a data object may have both sign and decrypt CLEAR
496 // BTW, since we know that decrypt==sign, no need to check both
7.6.3.6 FillInCreationData()
529 void
530 FillInCreationData(
531 TPMI_DH_OBJECT parentHandle, // IN: handle of parent
532 TPMI_ALG_HASH nameHashAlg, // IN: name hash algorithm
533 TPML_PCR_SELECTION *creationPCR, // IN: PCR selection
534 TPM2B_DATA *outsideData, // IN: outside data
535 TPM2B_CREATION_DATA *outCreation, // OUT: creation data for output
536 TPM2B_DIGEST *creationDigest // OUT: creation digest
537 )
538 {
539 BYTE creationBuffer[sizeof(TPMS_CREATION_DATA)];
540 BYTE *buffer;
541 HASH_STATE hashState;
542 //
543 // Fill in TPMS_CREATION_DATA in outCreation
544
545 // Compute PCR digest
546 PCRComputeCurrentDigest(nameHashAlg, creationPCR,
547 &outCreation->creationData.pcrDigest);
548
549 // Put back PCR selection list
550 outCreation->creationData.pcrSelect = *creationPCR;
551
552 // Get locality
553 outCreation->creationData.locality
554 = LocalityGetAttributes(_plat__LocalityGet());
555 outCreation->creationData.parentNameAlg = TPM_ALG_NULL;
556
557 // If the parent is either a primary seed or TPM_ALG_NULL, then the Name
558 // and QN of the parent are the parent's handle.
559 if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
560 {
561 buffer = &outCreation->creationData.parentName.t.name[0];
562 outCreation->creationData.parentName.t.size =
563 TPM_HANDLE_Marshal(&parentHandle, &buffer, NULL);
564 // For a primary or temporary object, the parent name (a handle) and the
565 // parent's QN are the same
566 outCreation->creationData.parentQualifiedName
567 = outCreation->creationData.parentName;
568 }
569 else // Regular object
570 {
571 OBJECT *parentObject = HandleToObject(parentHandle);
572 //
573 // Set name algorithm
574 outCreation->creationData.parentNameAlg = parentObject->publicArea.nameAlg;
575
576 // Copy parent name
577 outCreation->creationData.parentName = parentObject->name;
578
579 // Copy parent qualified name
580 outCreation->creationData.parentQualifiedName = parentObject->qualifiedName;
581 }
582 // Copy outside information
583 outCreation->creationData.outsideInfo = *outsideData;
584
585 // Marshal creation data to canonical form
586 buffer = creationBuffer;
587 outCreation->size = TPMS_CREATION_DATA_Marshal(&outCreation->creationData,
588 &buffer, NULL);
589 // Compute hash for creation field in public template
590 creationDigest->t.size = CryptHashStart(&hashState, nameHashAlg);
591 CryptDigestUpdate(&hashState, outCreation->size, creationBuffer);
592 CryptHashEnd2B(&hashState, &creationDigest->b);
593
594 return;
595 }
7.6.3.7 GetSeedForKDF()
Get a seed for KDF. The KDF for encryption and HMAC key use the same seed.
7.6.3.8 ProduceOuterWrap()
This function produce outer wrap for a buffer containing the sensitive data. It requires the sensitive data
being marshaled to the outerBuffer, with the leading bytes reserved for integrity hash. If iv is used, iv
space should be reserved at the beginning of the buffer. It assumes the sensitive data starts at address
(outerBuffer + integrity size [+ iv size]). This function performs:
Add IV before sensitive area if required
encrypt sensitive data, if iv is required, encrypt by iv. otherwise, encrypted by a NULL iv
add HMAC integrity at the beginning of the buffer It returns the total size of blob with outer wrap
610 UINT16
611 ProduceOuterWrap(
612 OBJECT *protector, // IN: The handle of the object that provides
613 // protection. For object, it is parent
614 // handle. For credential, it is the handle
615 // of encrypt object.
616 TPM2B *name, // IN: the name of the object
617 TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
618 TPM2B *seed, // IN: an external seed may be provided for
619 // duplication blob. For non duplication
620 // blob, this parameter should be NULL
621 BOOL useIV, // IN: indicate if an IV is used
622 UINT16 dataSize, // IN: the size of sensitive data, excluding the
623 // leading integrity buffer size or the
624 // optional iv size
625 BYTE *outerBuffer // IN/OUT: outer buffer with sensitive data in
626 // it
627 )
628 {
629 TPM_ALG_ID symAlg;
630 UINT16 keyBits;
631 TPM2B_SYM_KEY symKey;
632 TPM2B_IV ivRNG; // IV from RNG
633 TPM2B_IV *iv = NULL;
634 UINT16 ivSize = 0; // size of iv area, including the size field
635 BYTE *sensitiveData; // pointer to the sensitive data
636 TPM2B_DIGEST integrity;
637 UINT16 integritySize;
638 BYTE *buffer; // Auxiliary buffer pointer
639 //
640 // Compute the beginning of sensitive data. The outer integrity should
641 // always exist if this function is called to make an outer wrap
642 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
643 sensitiveData = outerBuffer + integritySize;
644
645 // If iv is used, adjust the pointer of sensitive data and add iv before it
646 if(useIV)
647 {
648 ivSize = GetIV2BSize(protector);
649
650 // Generate IV from RNG. The iv data size should be the total IV area
651 // size minus the size of size field
652 ivRNG.t.size = ivSize - sizeof(UINT16);
653 CryptRandomGenerate(ivRNG.t.size, ivRNG.t.buffer);
654
655 // Marshal IV to buffer
656 buffer = sensitiveData;
657 TPM2B_IV_Marshal(&ivRNG, &buffer, NULL);
658
659 // adjust sensitive data starting after IV area
660 sensitiveData += ivSize;
661
7.6.3.9 UnwrapOuter()
This function remove the outer wrap of a blob containing sensitive data This function performs:
check integrity of outer blob
decrypt outer blob
683 TPM_RC
684 UnwrapOuter(
685 OBJECT *protector, // IN: The object that provides
686 // protection. For object, it is parent
687 // handle. For credential, it is the
688 // encrypt object.
689 TPM2B *name, // IN: the name of the object
690 TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
691 TPM2B *seed, // IN: an external seed may be provided for
692 // duplication blob. For non duplication
693 // blob, this parameter should be NULL.
694 BOOL useIV, // IN: indicates if an IV is used
695 UINT16 dataSize, // IN: size of sensitive data in outerBuffer,
696 // including the leading integrity buffer
697 // size, and an optional iv area
698 BYTE *outerBuffer // IN/OUT: sensitive data
699 )
700 {
701 TPM_RC result;
702 TPM_ALG_ID symAlg = TPM_ALG_NULL;
703 TPM2B_SYM_KEY symKey;
704 UINT16 keyBits = 0;
705 TPM2B_IV ivIn; // input IV retrieved from input buffer
706 TPM2B_IV *iv = NULL;
707 BYTE *sensitiveData; // pointer to the sensitive data
7.6.3.10 MarshalSensitive()
This function is used to marshal a sensitive area. Among other things, it adjusts the size of the authValue
to be no smaller than the digest of nameAlg Returns the size of the marshaled area.
766 buffer += 2;
767
768 // Marshal the structure
769 #if ALG_RSA
770 // If the sensitive size is the special case for a prime in the type
771 if((sensitive->sensitive.rsa.t.size & RSA_prime_flag) > 0)
772 {
773 UINT16 sizeSave = sensitive->sensitive.rsa.t.size;
774 //
775 // Turn off the flag that indicates that the sensitive->sensitive contains
776 // the CRT form of the exponent.
777 sensitive->sensitive.rsa.t.size &= ~(RSA_prime_flag);
778 // If the parent isn't fixedTPM, then truncate the sensitive data to be
779 // the size of the prime. Otherwise, leave it at the current size which
780 // is the full CRT size.
781 if(parent == NULL
782 || !IS_ATTRIBUTE(parent->publicArea.objectAttributes,
783 TPMA_OBJECT, fixedTPM))
784 sensitive->sensitive.rsa.t.size /= 5;
785 retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
786 // Restore the flag and the size.
787 sensitive->sensitive.rsa.t.size = sizeSave;
788 }
789 else
790 #endif
791 retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
792
793 // Marshal the size
794 retVal = (UINT16)(retVal + UINT16_Marshal(&retVal, &sizeField, NULL));
795
796 return retVal;
797 }
7.6.3.11 SensitiveToPrivate()
This function prepare the private blob for off the chip storage The operations in this function:
marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
apply encryption to the sensitive area.
apply outer integrity computation.
798 void
799 SensitiveToPrivate(
800 TPMT_SENSITIVE *sensitive, // IN: sensitive structure
801 TPM2B_NAME *name, // IN: the name of the object
802 OBJECT *parent, // IN: The parent object
803 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. This
804 // parameter is used when parentHandle is
805 // NULL, in which case the object is
806 // temporary.
807 TPM2B_PRIVATE *outPrivate // OUT: output private structure
808 )
809 {
810 BYTE *sensitiveData; // pointer to the sensitive data
811 UINT16 dataSize; // data blob size
812 TPMI_ALG_HASH hashAlg; // hash algorithm for integrity
813 UINT16 integritySize;
814 UINT16 ivSize;
815 //
816 pAssert(name != NULL && name->t.size != 0);
817
818 // Find the hash algorithm for integrity computation
819 if(parent == NULL)
820 {
821 // For Temporary Object, using self name algorithm
822 hashAlg = nameAlg;
823 }
824 else
825 {
826 // Otherwise, using parent's name algorithm
827 hashAlg = parent->publicArea.nameAlg;
828 }
829 // Starting of sensitive data without wrappers
830 sensitiveData = outPrivate->t.buffer;
831
832 // Compute the integrity size
833 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
834
835 // Reserve space for integrity
836 sensitiveData += integritySize;
837
838 // Get iv size
839 ivSize = GetIV2BSize(parent);
840
841 // Reserve space for iv
842 sensitiveData += ivSize;
843
844 // Marshal the sensitive area including authValue size adjustments.
845 dataSize = MarshalSensitive(parent, sensitiveData, sensitive, nameAlg);
846
847 //Produce outer wrap, including encryption and HMAC
848 outPrivate->t.size = ProduceOuterWrap(parent, &name->b, hashAlg, NULL,
849 TRUE, dataSize, outPrivate->t.buffer);
850 return;
851 }
7.6.3.12 PrivateToSensitive()
Unwrap a input private area. Check the integrity, decrypt and retrieve data to a sensitive structure. The
operations in this function:
check the integrity HMAC of the input private area
decrypt the private buffer
unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
852 TPM_RC
853 PrivateToSensitive(
854 TPM2B *inPrivate, // IN: input private structure
855 TPM2B *name, // IN: the name of the object
856 OBJECT *parent, // IN: parent object
857 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It is
858 // passed separately because we only pass
859 // name, rather than the whole public area
860 // of the object. This parameter is used in
861 // the following two cases: 1. primary
862 // objects. 2. duplication blob with inner
7.6.3.13 SensitiveToDuplicate()
This function prepare the duplication blob from the sensitive area. The operations in this function:
921 void
922 SensitiveToDuplicate(
923 TPMT_SENSITIVE *sensitive, // IN: sensitive structure
924 TPM2B *name, // IN: the name of the object
925 OBJECT *parent, // IN: The new parent object
926 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It
927 // is passed separately because we
928 // only pass name, rather than the
929 // whole public area of the object.
930 TPM2B *seed, // IN: the external seed. If external
931 // seed is provided with size of 0,
932 // no outer wrap should be applied
933 // to duplication blob.
934 TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
935 // symmetric key algorithm is NULL,
936 // no inner wrap should be applied.
937 TPM2B_DATA *innerSymKey, // IN/OUT: a symmetric key may be
938 // provided to encrypt the inner
939 // wrap of a duplication blob. May
940 // be generated here if needed.
941 TPM2B_PRIVATE *outPrivate // OUT: output private structure
942 )
943 {
944 BYTE *sensitiveData; // pointer to the sensitive data
945 TPMI_ALG_HASH outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap
946 TPMI_ALG_HASH innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap
947 UINT16 dataSize; // data blob size
948 BOOL doInnerWrap = FALSE;
949 BOOL doOuterWrap = FALSE;
950 //
951 // Make sure that name is provided
952 pAssert(name != NULL && name->size != 0);
953
954 // Make sure symDef and innerSymKey are not NULL
955 pAssert(symDef != NULL && innerSymKey != NULL);
956
957 // Starting of sensitive data without wrappers
958 sensitiveData = outPrivate->t.buffer;
959
960 // Find out if inner wrap is required
961 if(symDef->algorithm != TPM_ALG_NULL)
962 {
963 doInnerWrap = TRUE;
964
965 // Use self nameAlg as inner hash algorithm
966 innerHash = nameAlg;
967
968 // Adjust sensitive data pointer
969 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(innerHash);
970 }
971 // Find out if outer wrap is required
972 if(seed->size != 0)
973 {
974 doOuterWrap = TRUE;
975
976 // Use parent nameAlg as outer hash algorithm
977 outerHash = parent->publicArea.nameAlg;
978
979 // Adjust sensitive data pointer
980 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
981 }
982 // Marshal sensitive area
983 dataSize = MarshalSensitive(NULL, sensitiveData, sensitive, nameAlg);
984
985 // Apply inner wrap for duplication blob. It includes both integrity and
986 // encryption
987 if(doInnerWrap)
988 {
989 BYTE *innerBuffer = NULL;
990 BOOL symKeyInput = TRUE;
991 innerBuffer = outPrivate->t.buffer;
992 // Skip outer integrity space
993 if(doOuterWrap)
994 innerBuffer += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
995 dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
996 innerBuffer);
997 // Generate inner encryption key if needed
998 if(innerSymKey->t.size == 0)
999 {
1000 innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
1001 CryptRandomGenerate(innerSymKey->t.size, innerSymKey->t.buffer);
1002
1003 // TPM generates symmetric encryption. Set the flag to FALSE
1004 symKeyInput = FALSE;
1005 }
1006 else
1007 {
1008 // assume the input key size should matches the symmetric definition
1009 pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1010 }
1011
1012 // Encrypt inner buffer in place
1013 CryptSymmetricEncrypt(innerBuffer, symDef->algorithm,
1014 symDef->keyBits.sym, innerSymKey->t.buffer, NULL,
1015 TPM_ALG_CFB, dataSize, innerBuffer);
1016
1017 // If the symmetric encryption key is imported, clear the buffer for
1018 // output
1019 if(symKeyInput)
1020 innerSymKey->t.size = 0;
1021 }
1022 // Apply outer wrap for duplication blob. It includes both integrity and
1023 // encryption
1024 if(doOuterWrap)
1025 {
1026 dataSize = ProduceOuterWrap(parent, name, outerHash, seed, FALSE,
1027 dataSize, outPrivate->t.buffer);
1028 }
1029 // Data size for output
1030 outPrivate->t.size = dataSize;
1031
1032 return;
1033 }
7.6.3.14 DuplicateToSensitive()
Unwrap a duplication blob. Check the integrity, decrypt and retrieve data to a sensitive structure. The
operations in this function:
1034 TPM_RC
1035 DuplicateToSensitive(
1036 TPM2B *inPrivate, // IN: input private structure
1037 TPM2B *name, // IN: the name of the object
1038 OBJECT *parent, // IN: the parent
1039 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area.
1040 TPM2B *seed, // IN: an external seed may be provided.
1041 // If external seed is provided with
1042 // size of 0, no outer wrap is
1043 // applied
1044 TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
1045 // symmetric key algorithm is NULL,
1046 // no inner wrap is applied
1047 TPM2B *innerSymKey, // IN: a symmetric key may be provided
1048 // to decrypt the inner wrap of a
1049 // duplication blob.
1050 TPMT_SENSITIVE *sensitive // OUT: sensitive structure
1051 )
1052 {
1053 TPM_RC result;
1054 BYTE *buffer;
1055 INT32 size;
1056 BYTE *sensitiveData; // pointer to the sensitive data
1057 UINT16 dataSize;
1058 UINT16 dataSizeInput;
1059 //
1060 // Make sure that name is provided
1061 pAssert(name != NULL && name->size != 0);
1062
1063 // Make sure symDef and innerSymKey are not NULL
1064 pAssert(symDef != NULL && innerSymKey != NULL);
1065
1066 // Starting of sensitive data
1067 sensitiveData = inPrivate->buffer;
1068 dataSize = inPrivate->size;
1069
1070 // Find out if outer wrap is applied
1071 if(seed->size != 0)
1072 {
1073 // Use parent nameAlg as outer hash algorithm
1074 TPMI_ALG_HASH outerHash = parent->publicArea.nameAlg;
1075
1076 result = UnwrapOuter(parent, name, outerHash, seed, FALSE,
1077 dataSize, sensitiveData);
1078 if(result != TPM_RC_SUCCESS)
1079 return result;
1080 // Adjust sensitive data pointer and size
1081 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1082 dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1083 }
1084 // Find out if inner wrap is applied
1085 if(symDef->algorithm != TPM_ALG_NULL)
1086 {
1087 // assume the input key size matches the symmetric definition
1088 pAssert(innerSymKey->size == (symDef->keyBits.sym + 7) / 8);
1089
1090 // Decrypt inner buffer in place
1091 CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
1092 symDef->keyBits.sym, innerSymKey->buffer, NULL,
1093 TPM_ALG_CFB, dataSize, sensitiveData);
1094 // Check inner integrity
1095 result = CheckInnerIntegrity(name, nameAlg, dataSize, sensitiveData);
1096 if(result != TPM_RC_SUCCESS)
1097 return result;
1098 // Adjust sensitive data pointer and size
1099 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
1100 dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
1101 }
1102 // Unmarshal input data size
1103 buffer = sensitiveData;
1104 size = (INT32)dataSize;
1105 result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
1106 if(result == TPM_RC_SUCCESS)
1107 {
1108 if((dataSizeInput + sizeof(UINT16)) != dataSize)
1109 result = TPM_RC_SIZE;
1110 else
1111 {
1112 // Unmarshal sensitive buffer to sensitive structure
1113 result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
1114
1115 // if the results is OK make sure that all the data was unmarshaled
1116 if(result == TPM_RC_SUCCESS && size != 0)
1117 result = TPM_RC_SIZE;
1118 }
1119 }
1120 return result;
1121 }
7.6.3.15 SecretToCredential()
This function prepare the credential blob from a secret (a TPM2B_DIGEST) The operations in this
function:
marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
encrypt the private buffer, excluding the leading integrity HMAC area
compute integrity HMAC and append to the beginning of the buffer.
Set the total size of TPM2B_ID_OBJECT buffer
1122 void
1123 SecretToCredential(
1124 TPM2B_DIGEST *secret, // IN: secret information
1125 TPM2B *name, // IN: the name of the object
1126 TPM2B *seed, // IN: an external seed.
1127 OBJECT *protector, // IN: the protector
1128 TPM2B_ID_OBJECT *outIDObject // OUT: output credential
1129 )
1130 {
1131 BYTE *buffer; // Auxiliary buffer pointer
1132 BYTE *sensitiveData; // pointer to the sensitive data
1133 TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
1134 UINT16 dataSize; // data blob size
1135 //
1136 pAssert(secret != NULL && outIDObject != NULL);
1137
1138 // use protector's name algorithm as outer hash ????
1139 outerHash = protector->publicArea.nameAlg;
1140
1141 // Marshal secret area to credential buffer, leave space for integrity
1142 sensitiveData = outIDObject->t.credential
1143 + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1144 // Marshal secret area
1145 buffer = sensitiveData;
1146 dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, NULL);
1147
1148 // Apply outer wrap
1149 outIDObject->t.size = ProduceOuterWrap(protector, name, outerHash, seed, FALSE,
1150 dataSize, outIDObject->t.credential);
1151 return;
1152 }
7.6.3.16 CredentialToSecret()
Unwrap a credential. Check the integrity, decrypt and retrieve data to a TPM2B_DIGEST structure. The
operations in this function:
check the integrity HMAC of the input credential area
decrypt the credential buffer
unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1153 TPM_RC
1154 CredentialToSecret(
1155 TPM2B *inIDObject, // IN: input credential blob
1156 TPM2B *name, // IN: the name of the object
1157 TPM2B *seed, // IN: an external seed.
1158 OBJECT *protector, // IN: the protector
1159 TPM2B_DIGEST *secret // OUT: secret information
1160 )
1161 {
1162 TPM_RC result;
1163 BYTE *buffer;
1164 INT32 size;
1165 TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
1166 BYTE *sensitiveData; // pointer to the sensitive data
1167 UINT16 dataSize;
1168 //
1169 // use protector's name algorithm as outer hash
1170 outerHash = protector->publicArea.nameAlg;
1171
1172 // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1173 result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
1174 inIDObject->size, inIDObject->buffer);
1175 if(result == TPM_RC_SUCCESS)
1176 {
1177 // Compute the beginning of sensitive data
1178 sensitiveData = inIDObject->buffer
1179 + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1180 dataSize = inIDObject->size
7.6.3.17 MemoryRemoveTrailingZeros()
This function is used to adjust the length of an authorization value. It adjusts the size of the TPM2B so
that it does not include octets at the end of the buffer that contain zero. The function returns the number
of non-zero octets in the buffer.
1194 UINT16
1195 MemoryRemoveTrailingZeros(
1196 TPM2B_AUTH *auth // IN/OUT: value to adjust
1197 )
1198 {
1199 while((auth->t.size > 0) && (auth->t.buffer[auth->t.size - 1] == 0))
1200 auth->t.size--;
1201 return auth->t.size;
1202 }
7.6.3.18 SetLabelAndContext()
This function sets the label and context for a derived key. It is possible that label or context can end up
being an Empty Buffer.
1203 TPM_RC
1204 SetLabelAndContext(
1205 TPMS_DERIVE *labelContext, // IN/OUT: the recovered label and
1206 // context
1207 TPM2B_SENSITIVE_DATA *sensitive // IN: the sensitive data
1208 )
1209 {
1210 TPMS_DERIVE sensitiveValue;
1211 TPM_RC result;
1212 INT32 size;
1213 BYTE *buff;
1214 //
1215 // Unmarshal a TPMS_DERIVE from the TPM2B_SENSITIVE_DATA buffer
1216 // If there is something to unmarshal...
1217 if(sensitive->t.size != 0)
1218 {
1219 size = sensitive->t.size;
1220 buff = sensitive->t.buffer;
1221 result = TPMS_DERIVE_Unmarshal(&sensitiveValue, &buff, &size);
1222 if(result != TPM_RC_SUCCESS)
1223 return result;
1224 // If there was a label in the public area leave it there, otherwise, copy
1225 // the new value
1226 if(labelContext->label.t.size == 0)
1227 MemoryCopy2B(&labelContext->label.b, &sensitiveValue.label.b,
1228 sizeof(labelContext->label.t.buffer));
1229 // if there was a context string in publicArea, it overrides
1230 if(labelContext->context.t.size == 0)
1231 MemoryCopy2B(&labelContext->context.b, &sensitiveValue.context.b,
1232 sizeof(labelContext->label.t.buffer));
1233 }
1234 return TPM_RC_SUCCESS;
1235 }
7.6.3.19 UnmarshalToPublic()
Support function to unmarshal the template. This is used because the Input may be a TPMT_TEMPLATE
and that structure does not have the same size as a TPMT_PUBLIC because of the difference between
the unique and seed fields. If derive is not NULL, then the seed field is assumed to contain a label and
context that are unmarshaled into derive.
1236 TPM_RC
1237 UnmarshalToPublic(
1238 TPMT_PUBLIC *tOut, // OUT: output
1239 TPM2B_TEMPLATE *tIn, // IN:
1240 BOOL derivation, // IN: indicates if this is for a derivation
1241 TPMS_DERIVE *labelContext// OUT: label and context if derivation
1242 )
1243 {
1244 BYTE *buffer = tIn->t.buffer;
1245 INT32 size = tIn->t.size;
1246 TPM_RC result;
1247 //
1248 // make sure that tOut is zeroed so that there are no remnants from previous
1249 // uses
1250 MemorySet(tOut, 0, sizeof(TPMT_PUBLIC));
1251 // Unmarshal the components of the TPMT_PUBLIC up to the unique field
1252 result = TPMI_ALG_PUBLIC_Unmarshal(&tOut->type, &buffer, &size);
1253 if(result != TPM_RC_SUCCESS)
1254 return result;
1255 result = TPMI_ALG_HASH_Unmarshal(&tOut->nameAlg, &buffer, &size, FALSE);
1256 if(result != TPM_RC_SUCCESS)
1257 return result;
1258 result = TPMA_OBJECT_Unmarshal(&tOut->objectAttributes, &buffer, &size);
1259 if(result != TPM_RC_SUCCESS)
1260 return result;
1261 result = TPM2B_DIGEST_Unmarshal(&tOut->authPolicy, &buffer, &size);
1262 if(result != TPM_RC_SUCCESS)
1263 return result;
1264 result = TPMU_PUBLIC_PARMS_Unmarshal(&tOut->parameters, &buffer, &size,
1265 tOut->type);
1266 if(result != TPM_RC_SUCCESS)
1267 return result;
1268 // Now unmarshal a TPMS_DERIVE if this is for derivation
1269 if(derivation)
1270 result = TPMS_DERIVE_Unmarshal(labelContext, &buffer, &size);
1271 else
1272 // otherwise, unmarshal a TPMU_PUBLIC_ID
1273 result = TPMU_PUBLIC_ID_Unmarshal(&tOut->unique, &buffer, &size,
1274 tOut->type);
1275 // Make sure the template was used up
1276 if((result == TPM_RC_SUCCESS) && (size != 0))
1277 result = TPM_RC_SIZE;
1278 return result;
1279 }
7.6.3.20 ObjectSetExternal()
1280 void
1281 ObjectSetExternal(
1282 OBJECT *object
1283 )
1284 {
1285 object->attributes.external = SET;
1286 }
1 #include "Tpm.h"
2 #include "EncryptDecrypt_fp.h"
3 #include "EncryptDecrypt_spt_fp.h"
4 #if CC_EncryptDecrypt2
5 TPM_RC
6 EncryptDecryptShared(
7 TPMI_DH_OBJECT keyHandleIn,
8 TPMI_YES_NO decryptIn,
9 TPMI_ALG_SYM_MODE modeIn,
10 TPM2B_IV *ivIn,
11 TPM2B_MAX_BUFFER *inData,
12 EncryptDecrypt_Out *out
13 )
14 {
15 OBJECT *symKey;
16 UINT16 keySize;
17 UINT16 blockSize;
18 BYTE *key;
19 TPM_ALG_ID alg;
20 TPM_ALG_ID mode;
21 TPM_RC result;
22 BOOL OK;
23 // Input Validation
24 symKey = HandleToObject(keyHandleIn);
25 mode = symKey->publicArea.parameters.symDetail.sym.mode.sym;
26
27 // The input key should be a symmetric key
28 if(symKey->publicArea.type != TPM_ALG_SYMCIPHER)
29 return TPM_RCS_KEY + RC_EncryptDecrypt_keyHandle;
30 // The key must be unrestricted and allow the selected operation
31 OK = !IS_ATTRIBUTE(symKey->publicArea.objectAttributes,
32 TPMA_OBJECT, restricted);
33 if(YES == decryptIn)
34 OK = OK && IS_ATTRIBUTE(symKey->publicArea.objectAttributes,
35 TPMA_OBJECT, decrypt);
36 else
37 OK = OK && IS_ATTRIBUTE(symKey->publicArea.objectAttributes,
38 TPMA_OBJECT, sign);
39 if(!OK)
40 return TPM_RCS_ATTRIBUTES + RC_EncryptDecrypt_keyHandle;
41
42 // Make sure that key is an encrypt/decrypt key and not SMAC
43 if(!CryptSymModeIsValid(mode, TRUE))
44 return TPM_RCS_MODE + RC_EncryptDecrypt_keyHandle;
45
46 // If the key mode is not TPM_ALG_NULL...
47 // or TPM_ALG_NULL
48 if(mode != TPM_ALG_NULL)
49 {
50 // then the input mode has to be TPM_ALG_NULL or the same as the key
7.8.1 Introduction
This code implements the ACT update code. It does not use a mutex. This code uses a platform service
(_plat__ACT_UpdateCounter()) that returns false if the update is not accepted. If this occurs, then
TPM_RC_RETRY should be sent to the caller so that they can retry the operation later. The
implementation of this is platform dependent but the reference uses a simple flag to indicate that an
update is pending and the only process that can clear that flag is the process that does the actual update.
7.8.2 Includes
1 #include "Tpm.h"
2 #include "ACT_spt_fp.h"
3 #include "Platform_fp.h"
7.8.3 Functions
7.8.3.1 _ActResume()
This function does the resume processing for an ACT. It updates the saved count and turns signaling
back on if necessary.
4 static void
5 _ActResume(
6 UINT32 act, //IN: the act number
7 ACT_STATE *actData //IN: pointer to the saved ACT data
8 )
9 {
10 // If the act was non-zero, then restore the counter value.
11 if(actData->remaining > 0)
12 _plat__ACT_UpdateCounter(act, actData->remaining);
13 // if the counter was zero and the ACT signaling, enable the signaling.
14 else if(go.signaledACT & (1 << act))
15 _plat__ACT_SetSignaled(act, TRUE);
16 }
7.8.3.2 ActStartup()
17 BOOL
18 ActStartup(
19 STARTUP_TYPE type
20 )
21 {
22 // Reset all the ACT hardware
23 _plat__ACT_Initialize();
24
25 // For TPM_RESET or TPM_RESTART, the ACTs will all be disabled and the output
26 // de-asserted.
27 if(type != SU_RESUME)
28 {
29 go.signaledACT = 0;
30 #define CLEAR_ACT_POLICY(N) \
31 go.ACT_##N.hashAlg = TPM_ALG_NULL; \
32 go.ACT_##N.authPolicy.b.size = 0;
33
34 FOR_EACH_ACT(CLEAR_ACT_POLICY)
35
36 }
37 else
38 {
39 // Resume each of the implemented ACT
40 #define RESUME_ACT(N) _ActResume(0x##N, &go.ACT_##N);
41
42 FOR_EACH_ACT(RESUME_ACT)
43 }
44 s_ActUpdated = 0;
45 _plat__ACT_EnableTicks(TRUE);
46 return TRUE;
47 }
7.8.3.3 _ActSaveState()
Get the counter state and the signaled state for an ACT. If the ACT has not been updated since the last
time it was saved, then divide the count by 2.
48 static void
49 _ActSaveState(
50 UINT32 act,
51 P_ACT_STATE actData
52 )
53 {
54 actData->remaining = _plat__ACT_GetRemaining(act);
55 // If the ACT hasn't been updated since the last startup, then it should be
56 // be halved.
57 if((s_ActUpdated & (1 << act)) == 0)
58 {
59 // Don't halve if the count is set to max or if halving would make it zero
60 if((actData->remaining != UINT32_MAX) && (actData->remaining > 1))
61 actData->remaining /= 2;
62 }
63 if(_plat__ACT_GetSignaled(act))
64 go.signaledACT |= (1 << act);
65 }
7.8.3.4 ActGetSignaled()
This function returns the state of the signaled flag associated with an ACT.
66 BOOL
67 ActGetSignaled(
68 TPM_RH actHandle
69 )
70 {
71 UINT32 act = actHandle - TPM_RH_ACT_0;
72 //
73 return _plat__ACT_GetSignaled(act);
74 }
7.8.3.5 ActShutdown()
75 BOOL
76 ActShutdown(
77 TPM_SU state //IN: the type of the shutdown.
78 )
79 {
80 // if this is not shutdown state, then the only type of startup is TPM_RESTART
81 // so the timer values will be cleared. If this is shutdown state, get the current
82 // countdown and signaled values. Plus, if the counter has not been updated
83 // since the last restart, divide the time by 2 so that there is no attack on the
84 // countdown by saving the countdown state early and then not using the TPM.
85 if(state == TPM_SU_STATE)
86 {
87 // This will be populated as each of the ACT is queried
88 go.signaledACT = 0;
89 // Get the current count and the signaled state
90 #define SAVE_ACT_STATE(N) _ActSaveState(0x##N, &go.ACT_##N);
91
92 FOR_EACH_ACT(SAVE_ACT_STATE);
93 }
94 return TRUE;
95 }
7.8.3.6 ActIsImplemented()
This function determines if an ACT is implemented in both the TPM and the platform code.
96 BOOL
97 ActIsImplemented(
98 UINT32 act
99 )
100 {
101 #define CASE_ACT_
102 // This switch accounts for the TPM implemente values.
103 switch(act)
104 {
105 FOR_EACH_ACT(CASE_ACT_NUMBER)
106 // This ensures that the platorm implementes the values implemented by
107 // the TPM
108 return _plat__ACT_GetImplemented(act);
109 default:
110 break;
111 }
112 return FALSE;
113 }
7.8.3.7 ActCounterUpdate()
This function updates the ACT counter. If the counter already has a pending update, it returns
TPM_RC_RETRY so that the update can be tried again later.
114 TPM_RC
115 ActCounterUpdate(
116 TPM_RH handle, //IN: the handle of the act
117 UINT32 newValue //IN: the value to set in the ACT
118 )
119 {
120 UINT32 act;
121 TPM_RC result;
122 //
123 act = handle - TPM_RH_ACT_0;
124 // This should never fail, but...
125 if(!_plat__ACT_GetImplemented(act))
126 result = TPM_RC_VALUE;
127 else
128 {
129 // Will need to clear orderly so fail if we are orderly and NV is not available
130 if(NV_IS_ORDERLY)
131 RETURN_IF_NV_IS_NOT_AVAILABLE;
132 // if the attempt to update the counter fails, it means that there is an
133 // update pending so wait until it has occurred and then do an update.
134 if(!_plat__ACT_UpdateCounter(act, newValue))
135 result = TPM_RC_RETRY;
136 else
137 {
138 // Indicate that the ACT has been updated since last TPM2_Startup().
139 s_ActUpdated |= (UINT16)(1 << act);
140
141 // Need to clear the orderly flag
142 g_clearOrderly = TRUE;
143
144 result = TPM_RC_SUCCESS;
145 }
146 }
147 return result;
148 }
7.8.3.8 ActGetCapabilityData()
149 TPMI_YES_NO
150 ActGetCapabilityData(
151 TPM_HANDLE actHandle, // IN: the handle for the starting ACT
152 UINT32 maxCount, // IN: maximum allowed return values
153 TPML_ACT_DATA *actList // OUT: ACT data list
154 )
155 {
156 // Initialize output property list
157 actList->count = 0;
158
159 // Make sure that the starting handle value is in range (again)
160 if((actHandle < TPM_RH_ACT_0) || (actHandle > TPM_RH_ACT_F))
161 return FALSE;
162 // The maximum count of curves we may return is MAX_ECC_CURVES
163 if(maxCount > MAX_ACT_DATA)
164 maxCount = MAX_ACT_DATA;
165 // Scan the ACT data from the starting ACT
166 for(; actHandle <= TPM_RH_ACT_F; actHandle++)
167 {
168 UINT32 act = actHandle - TPM_RH_ACT_0;
169 if(actList->count < maxCount)
170 {
171 if(ActIsImplemented(act))
172 {
173 TPMS_ACT_DATA *actData = &actList->actData[actList->count];
174 //
175 memset(&actData->attributes, 0, sizeof(actData->attributes));
176 actData->handle = actHandle;
177 actData->timeout = _plat__ACT_GetRemaining(act);
178 actData->attributes.signaled = _plat__ACT_GetSignaled(act);
179 actList->count++;
180 }
181 }
182 else
183 {
184 if(_plat__ACT_GetImplemented(act))
185 return YES;
186 }
187 }
188 // If we get here, either all of the ACT values were put in the list, or the list
189 // was filled and there are no more ACT values to return
190 return NO;
191 }
8 Subsystem
8.1 CommandAudit.c
8.1.1 Introduction
8.1.2 Includes
1 #include "Tpm.h"
8.1.3 Functions
8.1.3.1 CommandAuditPreInstall_Init()
This function initializes the command audit list. This function simulates the behavior of manufacturing. A
function is used instead of a structure definition because this is easier than figuring out the initialization
value for a bit array.
This function would not be implemented outside of a manufacturing or simulation environment.
2 void
3 CommandAuditPreInstall_Init(
4 void
5 )
6 {
7 // Clear all the audit commands
8 MemorySet(gp.auditCommands, 0x00, sizeof(gp.auditCommands));
9
10 // TPM_CC_SetCommandCodeAuditStatus always being audited
11 CommandAuditSet(TPM_CC_SetCommandCodeAuditStatus);
12
13 // Set initial command audit hash algorithm to be context integrity hash
14 // algorithm
15 gp.auditHashAlg = CONTEXT_INTEGRITY_HASH_ALG;
16
17 // Set up audit counter to be 0
18 gp.auditCounter = 0;
19
20 // Write command audit persistent data to NV
21 NV_SYNC_PERSISTENT(auditCommands);
22 NV_SYNC_PERSISTENT(auditHashAlg);
23 NV_SYNC_PERSISTENT(auditCounter);
24
25 return;
26 }
8.1.3.2 CommandAuditStartup()
27 BOOL
28 CommandAuditStartup(
29 STARTUP_TYPE type // IN: start up type
30 )
31 {
32 if((type != SU_RESTART) && (type != SU_RESUME))
33 {
34 // Reset the digest size to initialize the digest
35 gr.commandAuditDigest.t.size = 0;
36 }
37 return TRUE;
38 }
8.1.3.3 CommandAuditSet()
This function will SET the audit flag for a command. This function will not SET the audit flag for a
command that is not implemented. This ensures that the audit status is not SET when
TPM2_GetCapability() is used to read the list of audited commands.
This function is only used by TPM2_SetCommandCodeAuditStatus().
The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the changes to be saved to
NV after it is setting and clearing bits.
39 BOOL
40 CommandAuditSet(
41 TPM_CC commandCode // IN: command code
42 )
43 {
44 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
45
46 // Only SET a bit if the corresponding command is implemented
47 if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX)
48 {
49 // Can't audit shutdown
50 if(commandCode != TPM_CC_Shutdown)
51 {
52 if(!TEST_BIT(commandIndex, gp.auditCommands))
53 {
54 // Set bit
55 SET_BIT(commandIndex, gp.auditCommands);
56 return TRUE;
57 }
58 }
59 }
60 // No change
61 return FALSE;
62 }
8.1.3.4 CommandAuditClear()
This function will CLEAR the audit flag for a command. It will not CLEAR the audit flag for
TPM_CC_SetCommandCodeAuditStatus().
This function is only used by TPM2_SetCommandCodeAuditStatus().
The actions in TPM2_SetCommandCodeAuditStatus() are expected to cause the changes to be saved to
NV after it is setting and clearing bits.
63 BOOL
64 CommandAuditClear(
65 TPM_CC commandCode // IN: command code
66 )
67 {
68 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
69
70 // Do nothing if the command is not implemented
71 if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX)
72 {
73 // The bit associated with TPM_CC_SetCommandCodeAuditStatus() cannot be
74 // cleared
75 if(commandCode != TPM_CC_SetCommandCodeAuditStatus)
76 {
77 if(TEST_BIT(commandIndex, gp.auditCommands))
78 {
79 // Clear bit
80 CLEAR_BIT(commandIndex, gp.auditCommands);
81 return TRUE;
82 }
83 }
84 }
85 // No change
86 return FALSE;
87 }
8.1.3.5 CommandAuditIsRequired()
88 BOOL
89 CommandAuditIsRequired(
90 COMMAND_INDEX commandIndex // IN: command index
91 )
92 {
93 // Check the bit map. If the bit is SET, command audit is required
94 return(TEST_BIT(commandIndex, gp.auditCommands));
95 }
8.1.3.6 CommandAuditCapGetCCList()
This function returns a list of commands that have their audit bit SET.
The list starts at the input commandCode.
96 TPMI_YES_NO
97 CommandAuditCapGetCCList(
98 TPM_CC commandCode, // IN: start command code
99 UINT32 count, // IN: count of returned TPM_CC
100 TPML_CC *commandList // OUT: list of TPM_CC
101 )
102 {
103 TPMI_YES_NO more = NO;
104 COMMAND_INDEX commandIndex;
105
106 // Initialize output handle list
107 commandList->count = 0;
108
109 // The maximum count of command we may return is MAX_CAP_CC
110 if(count > MAX_CAP_CC) count = MAX_CAP_CC;
111
112 // Find the implemented command that has a command code that is the same or
113 // higher than the input
114 // Collect audit commands
115 for(commandIndex = GetClosestCommandIndex(commandCode);
116 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
117 commandIndex = GetNextCommandIndex(commandIndex))
118 {
119 if(CommandAuditIsRequired(commandIndex))
120 {
121 if(commandList->count < count)
122 {
123 // If we have not filled up the return list, add this command
124 // code to its
125 TPM_CC cc = GET_ATTRIBUTE(s_ccAttr[commandIndex],
126 TPMA_CC, commandIndex);
127 if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
128 cc += (1 << 29);
129 commandList->commandCodes[commandList->count] = cc;
130 commandList->count++;
131 }
132 else
133 {
134 // If the return list is full but we still have command
135 // available, report this and stop iterating
136 more = YES;
137 break;
138 }
139 }
140 }
141
142 return more;
143 }
8.1.3.7 CommandAuditGetDigest
This command is used to create a digest of the commands being audited. The commands are processed
in ascending numeric order with a list of TPM_CC being added to a hash. This operates as if all the
audited command codes were concatenated and then hashed.
144 void
145 CommandAuditGetDigest(
8.2 DA.c
8.2.1 Introduction
This file contains the functions and data definitions relating to the dictionary attack logic.
1 #define DA_C
2 #include "Tpm.h"
8.2.3 Functions
8.2.3.1 DAPreInstall_Init()
This function initializes the DA parameters to their manufacturer-default values. The default values are
determined by a platform-specific specification.
This function should not be called outside of a manufacturing or simulation environment.
The DA parameters will be restored to these initial values by TPM2_Clear().
3 void
4 DAPreInstall_Init(
5 void
6 )
7 {
8 gp.failedTries = 0;
9 gp.maxTries = 3;
10 gp.recoveryTime = 1000; // in seconds (~16.67 minutes)
11 gp.lockoutRecovery = 1000; // in seconds
12 gp.lockOutAuthEnabled = TRUE; // Use of lockoutAuth is enabled
13
14 // Record persistent DA parameter changes to NV
15 NV_SYNC_PERSISTENT(failedTries);
16 NV_SYNC_PERSISTENT(maxTries);
17 NV_SYNC_PERSISTENT(recoveryTime);
18 NV_SYNC_PERSISTENT(lockoutRecovery);
19 NV_SYNC_PERSISTENT(lockOutAuthEnabled);
20
21 return;
22 }
8.2.3.2 DAStartup()
This function is called by TPM2_Startup() to initialize the DA parameters. In the case of Startup(CLEAR),
use of lockoutAuth will be enabled if the lockout recovery time is 0. Otherwise, lockoutAuth will not be
enabled until the TPM has been continuously powered for the lockoutRecovery time.
This function requires that NV be available and not rate limiting.
23 BOOL
24 DAStartup(
25 STARTUP_TYPE type // IN: startup type
26 )
27 {
28 NOT_REFERENCED(type);
29 #if !ACCUMULATE_SELF_HEAL_TIMER
30 _plat__TimerWasReset();
31 s_selfHealTimer = 0;
32 s_lockoutTimer = 0;
33 #else
34 if(_plat__TimerWasReset())
35 {
36 if(!NV_IS_ORDERLY)
37 {
38 // If shutdown was not orderly, then don't really know if go.time has
39 // any useful value so reset the timer to 0. This is what the tick
40 // was reset to
41 s_selfHealTimer = 0;
42 s_lockoutTimer = 0;
43 }
44 else
45 {
46 // If we know how much time was accumulated at the last orderly shutdown
47 // subtract that from the saved timer values so that they effectively
48 // have the accumulated values
49 s_selfHealTimer -= go.time;
50 s_lockoutTimer -= go.time;
51 }
52 }
53 #endif
54
55 // For any Startup(), if lockoutRecovery is 0, enable use of lockoutAuth.
56 if(gp.lockoutRecovery == 0)
57 {
58 gp.lockOutAuthEnabled = TRUE;
59 // Record the changes to NV
60 NV_SYNC_PERSISTENT(lockOutAuthEnabled);
61 }
62
63 // If DA has not been disabled and the previous shutdown is not orderly
64 // failedTries is not already at its maximum then increment 'failedTries'
65 if(gp.recoveryTime != 0
66 && gp.failedTries < gp.maxTries
67 && !IS_ORDERLY(g_prevOrderlyState))
68 {
69 #if USE_DA_USED
70 gp.failedTries += g_daUsed;
71 g_daUsed = FALSE;
72 #else
73 gp.failedTries++;
74 #endif
75 // Record the change to NV
76 NV_SYNC_PERSISTENT(failedTries);
77 }
78 // Before Startup, the TPM will not do clock updates. At startup, need to
79 // do a time update which will do the DA update.
80 TimeUpdate();
81
82 return TRUE;
83 }
8.2.3.3 DARegisterFailure()
This function is called when a authorization failure occurs on an entity that is subject to dictionary-attack
protection. When a DA failure is triggered, register the failure by resetting the relevant self-healing timer
to the current time.
84 void
85 DARegisterFailure(
86 TPM_HANDLE handle // IN: handle for failure
87 )
88 {
89 // Reset the timer associated with lockout if the handle is the lockoutAuth.
90 if(handle == TPM_RH_LOCKOUT)
91 s_lockoutTimer = g_time;
92 else
93 s_selfHealTimer = g_time;
94 return;
95 }
8.2.3.4 DASelfHeal()
This function is called to check if sufficient time has passed to allow decrement of failedTries or to re-
enable use of lockoutAuth.
This function should be called when the time interval is updated.
96 void
97 DASelfHeal(
98 void
99 )
100 {
101 // Regular authorization self healing logic
102 // If no failed authorization tries, do nothing. Otherwise, try to
103 // decrease failedTries
104 if(gp.failedTries != 0)
105 {
106 // if recovery time is 0, DA logic has been disabled. Clear failed tries
107 // immediately
108 if(gp.recoveryTime == 0)
109 {
110 gp.failedTries = 0;
111 // Update NV record
112 NV_SYNC_PERSISTENT(failedTries);
113 }
114 else
115 {
116 UINT64 decreaseCount;
117 #if 0 // Errata eliminates this code
118 // In the unlikely event that failedTries should become larger than
119 // maxTries
120 if(gp.failedTries > gp.maxTries)
121 gp.failedTries = gp.maxTries;
122 #endif
123 // How much can failedTries be decreased
124
125 // Cast s_selfHealTimer to an int in case it became negative at
126 // startup
127 decreaseCount = ((g_time - (INT64)s_selfHealTimer) / 1000)
128 / gp.recoveryTime;
129
130 if(gp.failedTries <= (UINT32)decreaseCount)
131 // should not set failedTries below zero
132 gp.failedTries = 0;
133 else
134 gp.failedTries -= (UINT32)decreaseCount;
135
136 // the cast prevents overflow of the product
137 s_selfHealTimer += (decreaseCount * (UINT64)gp.recoveryTime) * 1000;
138 if(decreaseCount != 0)
139 // If there was a change to the failedTries, record the changes
140 // to NV
141 NV_SYNC_PERSISTENT(failedTries);
142 }
143 }
144
145 // LockoutAuth self healing logic
146 // If lockoutAuth is enabled, do nothing. Otherwise, try to see if we
147 // may enable it
148 if(!gp.lockOutAuthEnabled)
149 {
150 // if lockout authorization recovery time is 0, a reboot is required to
151 // re-enable use of lockout authorization. Self-healing would not
152 // apply in this case.
153 if(gp.lockoutRecovery != 0)
154 {
155 if(((g_time - (INT64)s_lockoutTimer) / 1000) >= gp.lockoutRecovery)
156 {
157 gp.lockOutAuthEnabled = TRUE;
158 // Record the changes to NV
159 NV_SYNC_PERSISTENT(lockOutAuthEnabled);
160 }
161 }
162 }
163 return;
164 }
8.3 Hierarchy.c
8.3.1 Introduction
This file contains the functions used for managing and accessing the hierarchy-related values.
8.3.2 Includes
1 #include "Tpm.h"
8.3.3 Functions
8.3.3.1 HierarchyPreInstall()
This function performs the initialization functions for the hierarchy when the TPM is simulated. This
function should not be called if the TPM is not in a manufacturing mode at the manufacturer, or in a
simulated environment.
2 void
3 HierarchyPreInstall_Init(
4 void
5 )
6 {
7 // Allow lockout clear command
8 gp.disableClear = FALSE;
9
10 // Initialize Primary Seeds
11 gp.EPSeed.t.size = sizeof(gp.EPSeed.t.buffer);
12 gp.SPSeed.t.size = sizeof(gp.SPSeed.t.buffer);
13 gp.PPSeed.t.size = sizeof(gp.PPSeed.t.buffer);
14 #if (defined USE_PLATFORM_EPS) && (USE_PLATFORM_EPS != NO)
15 _plat__GetEPS(gp.EPSeed.t.size, gp.EPSeed.t.buffer);
16 #else
17 CryptRandomGenerate(gp.EPSeed.t.size, gp.EPSeed.t.buffer);
18 #endif
19 CryptRandomGenerate(gp.SPSeed.t.size, gp.SPSeed.t.buffer);
20 CryptRandomGenerate(gp.PPSeed.t.size, gp.PPSeed.t.buffer);
21
22 // Initialize owner, endorsement and lockout authorization
23 gp.ownerAuth.t.size = 0;
24 gp.endorsementAuth.t.size = 0;
25 gp.lockoutAuth.t.size = 0;
26
27 // Initialize owner, endorsement, and lockout policy
28 gp.ownerAlg = TPM_ALG_NULL;
29 gp.ownerPolicy.t.size = 0;
30 gp.endorsementAlg = TPM_ALG_NULL;
31 gp.endorsementPolicy.t.size = 0;
32 gp.lockoutAlg = TPM_ALG_NULL;
33 gp.lockoutPolicy.t.size = 0;
34
35 // Initialize ehProof, shProof and phProof
36 gp.phProof.t.size = sizeof(gp.phProof.t.buffer);
37 gp.shProof.t.size = sizeof(gp.shProof.t.buffer);
38 gp.ehProof.t.size = sizeof(gp.ehProof.t.buffer);
39 CryptRandomGenerate(gp.phProof.t.size, gp.phProof.t.buffer);
40 CryptRandomGenerate(gp.shProof.t.size, gp.shProof.t.buffer);
41 CryptRandomGenerate(gp.ehProof.t.size, gp.ehProof.t.buffer);
42
43 // Write hierarchy data to NV
44 NV_SYNC_PERSISTENT(disableClear);
45 NV_SYNC_PERSISTENT(EPSeed);
46 NV_SYNC_PERSISTENT(SPSeed);
47 NV_SYNC_PERSISTENT(PPSeed);
48 NV_SYNC_PERSISTENT(ownerAuth);
49 NV_SYNC_PERSISTENT(endorsementAuth);
50 NV_SYNC_PERSISTENT(lockoutAuth);
51 NV_SYNC_PERSISTENT(ownerAlg);
52 NV_SYNC_PERSISTENT(ownerPolicy);
53 NV_SYNC_PERSISTENT(endorsementAlg);
54 NV_SYNC_PERSISTENT(endorsementPolicy);
55 NV_SYNC_PERSISTENT(lockoutAlg);
56 NV_SYNC_PERSISTENT(lockoutPolicy);
57 NV_SYNC_PERSISTENT(phProof);
58 NV_SYNC_PERSISTENT(shProof);
59 NV_SYNC_PERSISTENT(ehProof);
60
61 return;
62 }
8.3.3.2 HierarchyStartup()
63 BOOL
64 HierarchyStartup(
65 STARTUP_TYPE type // IN: start up type
66 )
67 {
68 // phEnable is SET on any startup
69 g_phEnable = TRUE;
70
71 // Reset platformAuth, platformPolicy; enable SH and EH at TPM_RESET and
72 // TPM_RESTART
73 if(type != SU_RESUME)
74 {
75 gc.platformAuth.t.size = 0;
76 gc.platformPolicy.t.size = 0;
77 gc.platformAlg = TPM_ALG_NULL;
78
79 // enable the storage and endorsement hierarchies and the platformNV
80 gc.shEnable = gc.ehEnable = gc.phEnableNV = TRUE;
81 }
82
83 // nullProof and nullSeed are updated at every TPM_RESET
84 if((type != SU_RESTART) && (type != SU_RESUME))
85 {
86 gr.nullProof.t.size = sizeof(gr.nullProof.t.buffer);
87 CryptRandomGenerate(gr.nullProof.t.size, gr.nullProof.t.buffer);
88 gr.nullSeed.t.size = sizeof(gr.nullSeed.t.buffer);
89 CryptRandomGenerate(gr.nullSeed.t.size, gr.nullSeed.t.buffer);
90 }
91
92 return TRUE;
93 }
8.3.3.3 HierarchyGetProof()
This function finds the proof value associated with a hierarchy.It returns a pointer to the proof value.
94 TPM2B_PROOF *
95 HierarchyGetProof(
96 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy constant
97 )
98 {
99 TPM2B_PROOF *proof = NULL;
100
101 switch(hierarchy)
102 {
103 case TPM_RH_PLATFORM:
104 // phProof for TPM_RH_PLATFORM
105 proof = &gp.phProof;
106 break;
107 case TPM_RH_ENDORSEMENT:
108 // ehProof for TPM_RH_ENDORSEMENT
109 proof = &gp.ehProof;
110 break;
111 case TPM_RH_OWNER:
112 // shProof for TPM_RH_OWNER
113 proof = &gp.shProof;
114 break;
115 default:
116 // nullProof for TPM_RH_NULL or anything else
117 proof = &gr.nullProof;
118 break;
119 }
120 return proof;
121 }
8.3.3.4 HierarchyGetPrimarySeed()
122 TPM2B_SEED *
123 HierarchyGetPrimarySeed(
124 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
125 )
126 {
127 TPM2B_SEED *seed = NULL;
128 switch(hierarchy)
129 {
130 case TPM_RH_PLATFORM:
131 seed = &gp.PPSeed;
132 break;
133 case TPM_RH_OWNER:
134 seed = &gp.SPSeed;
135 break;
136 case TPM_RH_ENDORSEMENT:
137 seed = &gp.EPSeed;
138 break;
139 default:
140 seed = &gr.nullSeed;
141 break;
142 }
143 return seed;
144 }
8.3.3.5 HierarchyIsEnabled()
145 BOOL
146 HierarchyIsEnabled(
147 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
148 )
149 {
150 BOOL enabled = FALSE;
151
152 switch(hierarchy)
153 {
154 case TPM_RH_PLATFORM:
155 enabled = g_phEnable;
156 break;
157 case TPM_RH_OWNER:
158 enabled = gc.shEnable;
159 break;
160 case TPM_RH_ENDORSEMENT:
161 enabled = gc.ehEnable;
162 break;
163 case TPM_RH_NULL:
164 enabled = TRUE;
165 break;
166 default:
167 enabled = FALSE;
168 break;
169 }
170 return enabled;
171 }
8.4 NvDynamic.c
8.4.1 Introduction
The NV memory is divided into two area: dynamic space for user defined NV indexes and evict objects,
and reserved space for TPM persistent and state save data.
The entries in dynamic space are a linked list of entries. Each entry has, as its first field, a size. If the size
field is zero, it marks the end of the list.
An Index allocation will contain an NV_INDEX structure. If the Index does not have the orderly attribute,
the NV_INDEX is followed immediately by the NV data.
An evict object entry contains a handle followed by an OBJECT structure. This results in both the Index
and Evict Object having an identifying handle as the first field following the size field.
When an Index has the orderly attribute, the data is kept in RAM. This RAM is saved to backing store in
NV memory on any orderly shutdown. The entries in orderly memory are also a linked list using a size
field as the first entry.
The attributes of an orderly index are maintained in RAM memory in order to reduce the number of NV
writes needed for orderly data. When an orderly index is created, an entry is made in the dynamic NV
memory space that holds the Index authorizations (authPolicy and authValue) and the size of the data.
This entry is only modified if the authValue of the index is changed. The more volatile data of the index is
kept in RAM. When an orderly Index is created or deleted, the RAM data is copied to NV backing store so
that the image in the backing store matches the layout of RAM. In normal operation. The RAM data is
also copied on any orderly shutdown. In normal operation, the only other reason for writing to the backing
store for RAM is when a counter is first written (TPMA_NV_WRITTEN changes from CLEAR to SET) or
when a counter "rolls over."
Static space contains items that are individually modifiable. The values are in the gp
PERSISTEND_DATA structure in RAM and mapped to locations in NV.
1 #define NV_C
2 #include "Tpm.h"
8.4.3.1 NvNext()
This function provides a method to traverse every data entry in NV dynamic area.
To begin with, parameter iter should be initialized to NV_REF_INIT indicating the first element. Every time
this function is called, the value in iter would be adjusted pointing to the next element in traversal. If there
is no next element, iter value would be 0. This function returns the address of the 'data entry' pointed by
the iter. If there is no more element in the set, a 0 value is returned indicating the end of traversal.
3 static NV_REF
4 NvNext(
5 NV_REF *iter, // IN/OUT: the list iterator
6 TPM_HANDLE *handle // OUT: the handle of the next item.
7 )
8 {
9 NV_REF currentAddr;
10 NV_ENTRY_HEADER header;
11 //
12 // If iterator is at the beginning of list
13 if(*iter == NV_REF_INIT)
14 {
15 // Initialize iterator
16 *iter = NV_USER_DYNAMIC;
17 }
18 // Step over the size field and point to the handle
19 currentAddr = *iter + sizeof(UINT32);
20
21 // read the header of the next entry
22 NvRead(&header, *iter, sizeof(NV_ENTRY_HEADER));
23
24 // if the size field is zero, then we have hit the end of the list
25 if(header.size == 0)
26 // leave the *iter pointing at the end of the list
27 return 0;
28 // advance the header by the size of the entry
29 *iter += header.size;
30
31 if(handle != NULL)
32 *handle = header.handle;
33 return currentAddr;
34 }
8.4.3.2 NvNextByType()
This function returns a reference to the next NV entry of the desired type
35 static NV_REF
36 NvNextByType(
37 TPM_HANDLE *handle, // OUT: the handle of the found type
38 NV_REF *iter, // IN: the iterator
39 TPM_HT type // IN: the handle type to look for
40 )
41 {
42 NV_REF addr;
43 TPM_HANDLE nvHandle;
44 //
45 while((addr = NvNext(iter, &nvHandle)) != 0)
46 {
47 // addr: the address of the location containing the handle of the value
48 // iter: the next location.
49 if(HandleGetType(nvHandle) == type)
50 break;
51 }
52 if(handle != NULL)
53 *handle = nvHandle;
54 return addr;
55 }
8.4.3.3 NvNextIndex()
This function returns the reference to the next NV Index entry. A value of 0 indicates the end of the list.
8.4.3.4 NvNextEvict()
This function returns the offset in NV of the next evict object entry. A value of 0 indicates the end of the
list.
8.4.3.5 NvGetEnd()
60 static NV_REF
61 NvGetEnd(
62 void
63 )
64 {
65 NV_REF iter = NV_REF_INIT;
66 NV_REF currentAddr;
67 //
68 // Scan until the next address is 0
69 while((currentAddr = NvNext(&iter, NULL)) != 0);
70 return iter;
71 }
8.4.3.6 NvGetFreeBytes
72 static UINT32
73 NvGetFreeBytes(
74 void
75 )
76 {
77 // This does not have an overflow issue because NvGetEnd() cannot return a value
78 // that is larger than s_evictNvEnd. This is because there is always a 'stop'
79 // word in the NV memory that terminates the search for the end before the
80 // value can go past s_evictNvEnd.
81 return s_evictNvEnd - NvGetEnd();
82 }
8.4.3.7 NvTestSpace()
This function will test if there is enough space to add a new entity.
83 static BOOL
84 NvTestSpace(
85 UINT32 size, // IN: size of the entity to be added
86 BOOL isIndex, // IN: TRUE if the entity is an index
87 BOOL isCounter // IN: TRUE if the index is a counter
88 )
89 {
90 UINT32 remainBytes = NvGetFreeBytes();
91 UINT32 reserved = sizeof(UINT32) // size of the forward pointer
92 + sizeof(NV_LIST_TERMINATOR);
93 //
94 // Do a compile time sanity check on the setting for NV_MEMORY_SIZE
95 #if NV_MEMORY_SIZE < 1024
96 #error "NV_MEMORY_SIZE probably isn't large enough"
97 #endif
98
99 // For NV Index, need to make sure that we do not allocate an Index if this
100 // would mean that the TPM cannot allocate the minimum number of evict
101 // objects.
102 if(isIndex)
103 {
104 // Get the number of persistent objects allocated
105 UINT32 persistentNum = NvCapGetPersistentNumber();
106
107 // If we have not allocated the requisite number of evict objects, then we
108 // need to reserve space for them.
109 // NOTE: some of this is not written as simply as it might seem because
110 // the values are all unsigned and subtracting needs to be done carefully
111 // so that an underflow doesn't cause problems.
112 if(persistentNum < MIN_EVICT_OBJECTS)
113 reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
114 }
115 // If this is not an index or is not a counter, reserve space for the
116 // required number of counter indexes
117 if(!isIndex || !isCounter)
118 {
119 // Get the number of counters
120 UINT32 counterNum = NvCapGetCounterNumber();
121
122 // If the required number of counters have not been allocated, reserved
123 // space for the extra needed counters
124 if(counterNum < MIN_COUNTER_INDICES)
125 reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
126 }
127 // Check that the requested allocation will fit after making sure that there
128 // will be no chance of overflow
129 return ((reserved < remainBytes)
130 && (size <= remainBytes)
131 && (size + reserved <= remainBytes));
132 }
8.4.3.8 NvWriteNvListEnd()
133 NV_REF
134 NvWriteNvListEnd(
135 NV_REF end
136 )
137 {
138 // Marker is initialized with zeros
139 BYTE listEndMarker[sizeof(NV_LIST_TERMINATOR)] = {0};
140 UINT64 maxCount = NvReadMaxCount();
141 //
142 // This is a constant check that can be resolved at compile time.
143 cAssert(sizeof(UINT64) <= sizeof(NV_LIST_TERMINATOR) - sizeof(UINT32));
144
145 // Copy the maxCount value to the marker buffer
146 MemoryCopy(&listEndMarker[sizeof(UINT32)], &maxCount, sizeof(UINT64));
147 pAssert(end + sizeof(NV_LIST_TERMINATOR) <= s_evictNvEnd);
148
149 // Write it to memory
150 NvWrite(end, sizeof(NV_LIST_TERMINATOR), &listEndMarker);
151 return end + sizeof(NV_LIST_TERMINATOR);
152 }
8.4.3.9 NvAdd()
8.4.3.10 NvDelete()
8.4.4.1 Introduction
The data layout in ram buffer is {size of(NV_handle + attributes + data NV_handle, attributes, data} for
each NV Index data stored in RAM.
NV storage associated with orderly data is updated when a NV Index is added but NOT when the data or
attributes are changed. Orderly data is only updated to NV on an orderly shutdown (TPM2_Shutdown())
8.4.4.2 NvRamNext()
This function is used to iterate trough the list of Ram Index values. *iter needs to be initialized by calling
8.4.4.3 NvRamGetEnd()
This routine performs the same function as NvGetEnd() but for the RAM data.
287 {
288 NV_RAM_REF iter = NV_RAM_REF_INIT;
289 NV_RAM_REF currentAddr;
290 //
291 // Scan until the next address is 0
292 while((currentAddr = NvRamNext(&iter, NULL)) != 0);
293 return iter;
294 }
8.4.4.4 NvRamTestSpaceIndex()
This function indicates if there is enough RAM space to add a data for a new NV Index.
8.4.4.5 NvRamGetIndex()
8.4.4.6 NvUpdateIndexOrderlyData()
This function is used to cause an update of the orderly data to the NV backing store.
322 void
323 NvUpdateIndexOrderlyData(
324 void
325 )
326 {
327 // Write reserved RAM space to NV
328 NvWrite(NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam), s_indexOrderlyRam);
329 }
8.4.4.7 NvAddRAM()
8.4.4.8 NvDeleteRAM()
This function is used to delete a RAM-backed NV Index data area. The space used by the entry are
overwritten by the contents of the Index data that comes after (the data is moved up to fill the hole left by
removing this index. The reclaimed space is cleared to zeros. This function assumes the data of NV Index
exists in RAM.
This function should be called after the NV Index space has been updated and the index removed. This
insures that NV is available so that checking for NV availability is not required during this function.
8.4.4.9 NvReadIndex()
This function is used to read the NV Index NV_INDEX. This is used so that the index information can be
compressed and only this function would be needed to decompress it. Mostly, compression would only be
able to save the space needed by the policy.
392 void
393 NvReadNvIndexInfo(
394 NV_REF ref, // IN: points to NV where index is located
395 NV_INDEX *nvIndex // OUT: place to receive index data
396 )
397 {
398 pAssert(nvIndex != NULL);
399 NvRead(nvIndex, ref, sizeof(NV_INDEX));
400 return;
401 }
8.4.4.10 NvReadObject()
This function is used to read a persistent object. This is used so that the object information can be
compressed and only this function would be needed to uncompress it.
402 void
403 NvReadObject(
404 NV_REF ref, // IN: points to NV where index is located
405 OBJECT *object // OUT: place to receive the object data
406 )
407 {
408 NvRead(object, (ref + sizeof(TPM_HANDLE)), sizeof(OBJECT));
409 return;
410 }
8.4.4.11 NvFindEvict()
8.4.4.12 NvIndexIsDefined()
424 BOOL
425 NvIndexIsDefined(
426 TPM_HANDLE nvHandle // IN: Index to look for
427 )
428 {
429 return (NvFindHandle(nvHandle) != 0);
430 }
8.4.4.13 NvConditionallyWrite()
Function to check if the data to be written has changed and write it if it has
8.4.4.14 NvReadNvIndexAttributes()
8.4.4.15 NvReadRamIndexAttributes()
This function returns the attributes from the RAM header structure. This function is used to deal with the
fact that the header structure is only byte aligned.
8.4.4.16 NvWriteNvIndexAttributes()
8.4.4.17 NvWriteRamIndexAttributes()
This function is used to write the index attributes into an unaligned structure
8.4.5.1 NvIsPlatformPersistentHandle()
This function indicates if a handle references a persistent object in the range belonging to the platform.
494 BOOL
495 NvIsPlatformPersistentHandle(
496 TPM_HANDLE handle // IN: handle
497 )
498 {
499 return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
500 }
8.4.5.2 NvIsOwnerPersistentHandle()
This function indicates if a handle references a persistent object in the range belonging to the owner.
501 BOOL
502 NvIsOwnerPersistentHandle(
503 TPM_HANDLE handle // IN: handle
504 )
505 {
506 return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
507 }
8.4.5.3 NvIndexIsAccessible()
This function validates that a handle references a defined NV Index and that the Index is currently
accessible.
508 TPM_RC
509 NvIndexIsAccessible(
510 TPMI_RH_NV_INDEX handle // IN: handle
511 )
512 {
513 NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL);
514 //
515 if(nvIndex == NULL)
516 // If index is not found, return TPM_RC_HANDLE
517 return TPM_RC_HANDLE;
518 if(gc.shEnable == FALSE || gc.phEnableNV == FALSE)
519 {
520 // if shEnable is CLEAR, an ownerCreate NV Index should not be
521 // indicated as present
522 if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE))
523 {
524 if(gc.shEnable == FALSE)
525 return TPM_RC_HANDLE;
526 }
527 // if phEnableNV is CLEAR, a platform created Index should not
528 // be visible
529 else if(gc.phEnableNV == FALSE)
530 return TPM_RC_HANDLE;
531 }
532 #if 0 // Writelock test for debug
533 // If the Index is write locked and this is an NV Write operation...
534 if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITELOCKED)
535 && IsWriteOperation(commandIndex))
536 {
537 // then return a locked indication unless the command is TPM2_NV_WriteLock
538 if(GetCommandCode(commandIndex) != TPM_CC_NV_WriteLock)
539 return TPM_RC_NV_LOCKED;
540 return TPM_RC_SUCCESS;
541 }
542 #endif
543 #if 0 // Readlock Test for debug
544 // If the Index is read locked and this is an NV Read operation...
545 if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, READLOCKED)
546 && IsReadOperation(commandIndex))
547 {
548 // then return a locked indication unless the command is TPM2_NV_ReadLock
549 if(GetCommandCode(commandIndex) != TPM_CC_NV_ReadLock)
550 return TPM_RC_NV_LOCKED;
551 }
552 #endif
553 // NV Index is accessible
554 return TPM_RC_SUCCESS;
555 }
8.4.5.4 NvGetEvictObject()
This function is used to dereference an evict object handle and get a pointer to the object.
556 TPM_RC
557 NvGetEvictObject(
558 TPM_HANDLE handle, // IN: handle
559 OBJECT *object // OUT: object data
560 )
561 {
562 NV_REF entityAddr; // offset points to the entity
563 //
564 // Find the address of evict object and copy to object
565 entityAddr = NvFindEvict(handle, object);
566
567 // whether there is an error or not, make sure that the evict
568 // status of the object is set so that the slot will get freed on exit
569 // Must do this after NvFindEvict loads the object
570 object->attributes.evict = SET;
571
572 // If handle is not found, return an error
573 if(entityAddr == 0)
574 return TPM_RC_HANDLE;
575 return TPM_RC_SUCCESS;
576 }
8.4.5.5 NvIndexCacheInit()
577 void
578 NvIndexCacheInit(
579 void
580 )
581 {
582 s_cachedNvRef = NV_REF_INIT;
583 s_cachedNvRamRef = NV_RAM_REF_INIT;
584 s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
585 return;
586 }
8.4.5.6 NvGetIndexData()
This function is used to access the data in an NV Index. The data is returned as a byte sequence.
This function requires that the NV Index be defined, and that the required data is within the data range. It
also requires that TPMA_NV_WRITTEN of the Index is SET.
587 void
588 NvGetIndexData(
589 NV_INDEX *nvIndex, // IN: the in RAM index descriptor
590 NV_REF locator, // IN: where the data is located
591 UINT32 offset, // IN: offset of NV data
592 UINT16 size, // IN: number of octets of NV data to read
593 void *data // OUT: data buffer
594 )
595 {
596 TPMA_NV nvAttributes;
597 //
598 pAssert(nvIndex != NULL);
599
600 nvAttributes = nvIndex->publicArea.attributes;
601
602 pAssert(IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN));
603
604 if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, ORDERLY))
605 {
606 // Get data from RAM buffer
607 NV_RAM_REF ramAddr = NvRamGetIndex(nvIndex->publicArea.nvIndex);
608 pAssert(ramAddr != 0 && (size <=
609 ((NV_RAM_HEADER *)ramAddr)->size - sizeof(NV_RAM_HEADER) - offset));
610 MemoryCopy(data, ramAddr + sizeof(NV_RAM_HEADER) + offset, size);
611 }
612 else
613 {
614 // Validate that read falls within range of the index
615 pAssert(offset <= nvIndex->publicArea.dataSize
616 && size <= (nvIndex->publicArea.dataSize - offset));
617 NvRead(data, locator + sizeof(NV_INDEX) + offset, size);
618 }
619 return;
620 }
8.4.5.7 NvHashIndexData()
This function adds Index data to a hash. It does this in parts to avoid large stack buffers.
621 void
622 NvHashIndexData(
623 HASH_STATE *hashState, // IN: Initialized hash state
624 NV_INDEX *nvIndex, // IN: Index
625 NV_REF locator, // IN: where the data is located
626 UINT32 offset, // IN: starting offset
627 UINT16 size // IN: amount to hash
628 )
629 {
630 #define BUFFER_SIZE 64
631 BYTE buffer[BUFFER_SIZE];
632 if (offset > nvIndex->publicArea.dataSize)
633 return;
634 // Make sure that we don't try to read off the end.
635 if ((offset + size) > nvIndex->publicArea.dataSize)
636 size = nvIndex->publicArea.dataSize - (UINT16)offset;
637 #if BUFFER_SIZE >= MAX_NV_INDEX_SIZE
638 NvGetIndexData(nvIndex, locator, offset, size, buffer);
639 CryptDigestUpdate(hashState, size, buffer);
640 #else
641 {
642 INT16 i;
643 UINT16 readSize;
644 //
645 for (i = size; i > 0; offset += readSize, i -= readSize)
646 {
647 readSize = (i < BUFFER_SIZE) ? i : BUFFER_SIZE;
648 NvGetIndexData(nvIndex, locator, offset, readSize, buffer);
649 CryptDigestUpdate(hashState, readSize, buffer);
650 }
651 }
652 #endif // BUFFER_SIZE >= MAX_NV_INDEX_SIZE
653 #undef BUFFER_SIZE
654 }
8.4.5.8 NvGetUINT64Data()
This function requires that the NV Index is defined and that the NV Index previously has been written.
655 UINT64
656 NvGetUINT64Data(
657 NV_INDEX *nvIndex, // IN: the in RAM index descriptor
658 NV_REF locator // IN: where index exists in NV
659 )
660 {
661 UINT64 intVal;
662 //
663 // Read the value and convert it to internal format
664 NvGetIndexData(nvIndex, locator, 0, 8, &intVal);
665 return BYTE_ARRAY_TO_UINT64(((BYTE *)&intVal));
666 }
8.4.5.9 NvWriteIndexAttributes()
667 TPM_RC
668 NvWriteIndexAttributes(
669 TPM_HANDLE handle,
670 NV_REF locator, // IN: location of the index
671 TPMA_NV attributes // IN: attributes to write
672 )
673 {
674 TPM_RC result;
675 //
676 if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
677 {
678 NV_RAM_REF ram = NvRamGetIndex(handle);
679 NvWriteRamIndexAttributes(ram, attributes);
680 result = TPM_RC_SUCCESS;
681 }
682 else
683 {
684 result = NvWriteNvIndexAttributes(locator, attributes);
685 }
686 return result;
687 }
8.4.5.10 NvWriteIndexAuth()
688 TPM_RC
689 NvWriteIndexAuth(
690 NV_REF locator, // IN: location of the index
691 TPM2B_AUTH *authValue // IN: the authValue to write
692 )
693 {
694 TPM_RC result;
695 //
696 // If the locator is pointing to the cached index value...
697 if(locator == s_cachedNvRef)
698 {
699 // copy the authValue to the cached index so it will be there if we
700 // look for it. This is a safety thing.
701 MemoryCopy2B(&s_cachedNvIndex.authValue.b, &authValue->b,
702 sizeof(s_cachedNvIndex.authValue.t.buffer));
703 }
704 result = NvConditionallyWrite(
705 locator + offsetof(NV_INDEX, authValue),
706 sizeof(UINT16) + authValue->t.size,
707 authValue);
708 return result;
709 }
8.4.5.11 NvGetIndexInfo()
This function loads the nvIndex Info into the NV cache and returns a pointer to the NV_INDEX. If the
returned value is zero, the index was not found. The locator parameter, if not NULL, will be set to the
offset in NV of the Index (the location of the handle of the Index).
This function will set the index cache. If the index is orderly, the attributes from RAM are substituted for
the attributes in the cached index
710 NV_INDEX *
711 NvGetIndexInfo(
712 TPM_HANDLE nvHandle, // IN: the index handle
713 NV_REF *locator // OUT: location of the index
714 )
715 {
716 if(s_cachedNvIndex.publicArea.nvIndex != nvHandle)
717 {
718 s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
719 s_cachedNvRamRef = 0;
720 s_cachedNvRef = NvFindHandle(nvHandle);
721 if(s_cachedNvRef == 0)
722 return NULL;
723 NvReadNvIndexInfo(s_cachedNvRef, &s_cachedNvIndex);
724 if(IS_ATTRIBUTE(s_cachedNvIndex.publicArea.attributes, TPMA_NV, ORDERLY))
725 {
726 s_cachedNvRamRef = NvRamGetIndex(nvHandle);
727 s_cachedNvIndex.publicArea.attributes =
728 NvReadRamIndexAttributes(s_cachedNvRamRef);
729 }
730 }
731 if(locator != NULL)
732 *locator = s_cachedNvRef;
733 return &s_cachedNvIndex;
734 }
8.4.5.12 NvWriteIndexData()
This function is used to write NV index data. It is intended to be used to update the data associated with
the default index.
This function requires that the NV Index is defined, and the data is within the defined data range for the
index.
Index data is only written due to a command that modifies the data in a single index. There is no case
where changes are made to multiple indexes data at the same time. Multiple attributes may be change
but not multiple index data. This is important because we will normally be handling the index for which we
have the cached pointer values.
735 TPM_RC
736 NvWriteIndexData(
737 NV_INDEX *nvIndex, // IN: the description of the index
738 UINT32 offset, // IN: offset of NV data
739 UINT32 size, // IN: size of NV data
740 void *data // IN: data buffer
741 )
742 {
743 TPM_RC result = TPM_RC_SUCCESS;
744 //
745 pAssert(nvIndex != NULL);
746 // Make sure that this is dealing with the 'default' index.
747 // Note: it is tempting to change the calling sequence so that the 'default' is
748 // presumed.
749 pAssert(nvIndex->publicArea.nvIndex == s_cachedNvIndex.publicArea.nvIndex);
750
751 // Validate that write falls within range of the index
752 pAssert(offset <= nvIndex->publicArea.dataSize
753 && size <= (nvIndex->publicArea.dataSize - offset));
754
755 // Update TPMA_NV_WRITTEN bit if necessary
756 if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
757 {
758 // Update the in memory version of the attributes
759 SET_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN);
760
761 // If this is not orderly, then update the NV version of
762 // the attributes
763 if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
764 {
765 result = NvWriteNvIndexAttributes(s_cachedNvRef,
766 nvIndex->publicArea.attributes);
767 if(result != TPM_RC_SUCCESS)
768 return result;
769 // If this is a partial write of an ordinary index, clear the whole
770 // index.
771 if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes)
772 && (nvIndex->publicArea.dataSize > size))
773 _plat__NvMemoryClear(s_cachedNvRef + sizeof(NV_INDEX),
774 nvIndex->publicArea.dataSize);
775 }
776 else
777 {
778 // This is orderly so update the RAM version
779 MemoryCopy(s_cachedNvRamRef + offsetof(NV_RAM_HEADER, attributes),
780 &nvIndex->publicArea.attributes, sizeof(TPMA_NV));
781 // If setting WRITTEN for an orderly counter, make sure that the
782 // state saved version of the counter is saved
783 if(IsNvCounterIndex(nvIndex->publicArea.attributes))
784 SET_NV_UPDATE(UT_ORDERLY);
785 // If setting the written attribute on an ordinary index, make sure that
786 // the data is all cleared out in case there is a partial write. This
787 // is only necessary for ordinary indexes because all of the other types
788 // are always written in total.
789 else if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes))
790 MemorySet(s_cachedNvRamRef + sizeof(NV_RAM_HEADER),
791 0, nvIndex->publicArea.dataSize);
792 }
793 }
794 // If this is orderly data, write it to RAM
795 if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
796 {
797 // Note: if this is the first write to a counter, the code above will queue
798 // the write to NV of the RAM data in order to update TPMA_NV_WRITTEN. In
799 // process of doing that write, it will also write the initial counter value
800
801 // Update RAM
802 MemoryCopy(s_cachedNvRamRef + sizeof(NV_RAM_HEADER) + offset, data, size);
803
804 // And indicate that the TPM is no longer orderly
805 g_clearOrderly = TRUE;
806 }
807 else
808 {
809 // Offset into the index to the first byte of the data to be written to NV
810 result = NvConditionallyWrite(s_cachedNvRef + sizeof(NV_INDEX) + offset,
811 size, data);
812 }
813 return result;
814 }
8.4.5.13 NvWriteUINT64Data()
This function to write back a UINT64 value. The various UINT64 values (bits, counters, and PINs) are
kept in canonical format but manipulate in native format. This takes a native format value converts it and
saves it back as in canonical format.
This function will return the value from NV or RAM depending on the type of the index (orderly or not)
815 TPM_RC
816 NvWriteUINT64Data(
817 NV_INDEX *nvIndex, // IN: the description of the index
818 UINT64 intValue // IN: the value to write
819 )
820 {
821 BYTE bytes[8];
822 UINT64_TO_BYTE_ARRAY(intValue, bytes);
823 //
824 return NvWriteIndexData(nvIndex, 0, 8, &bytes);
825 }
8.4.5.14 NvGetIndexName()
This function computes the Name of an index The name buffer receives the bytes of the Name and the
return value is the number of octets in the Name.
This function requires that the NV Index is defined.
826 TPM2B_NAME *
827 NvGetIndexName(
828 NV_INDEX *nvIndex, // IN: the index over which the name is to be
829 // computed
830 TPM2B_NAME *name // OUT: name of the index
831 )
832 {
833 UINT16 dataSize, digestSize;
834 BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)];
835 BYTE *buffer;
836 HASH_STATE hashState;
837 //
838 // Marshal public area
839 buffer = marshalBuffer;
840 dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex->publicArea, &buffer, NULL);
841
842 // hash public area
843 digestSize = CryptHashStart(&hashState, nvIndex->publicArea.nameAlg);
844 CryptDigestUpdate(&hashState, dataSize, marshalBuffer);
845
846 // Complete digest leaving room for the nameAlg
847 CryptHashEnd(&hashState, digestSize, &name->b.buffer[2]);
848
849 // Include the nameAlg
850 UINT16_TO_BYTE_ARRAY(nvIndex->publicArea.nameAlg, name->b.buffer);
851 name->t.size = digestSize + 2;
852 return name;
853 }
8.4.5.15 NvGetNameByIndexHandle()
854 TPM2B_NAME *
855 NvGetNameByIndexHandle(
856 TPMI_RH_NV_INDEX handle, // IN: handle of the index
857 TPM2B_NAME *name // OUT: name of the index
858 )
859 {
860 NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL);
861 //
862 return NvGetIndexName(nvIndex, name);
863 }
8.4.5.16 NvDefineIndex()
864 TPM_RC
865 NvDefineIndex(
866 TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create.
867 TPM2B_AUTH *authValue // IN: The initial authorization value
868 )
869 {
870 // The buffer to be written to NV memory
871 NV_INDEX nvIndex; // the index data
872 UINT16 entrySize; // size of entry
873 TPM_RC result;
874 //
875 entrySize = sizeof(NV_INDEX);
876
877 // only allocate data space for indexes that are going to be written to NV.
878 // Orderly indexes don't need space.
879 if(!IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
880 entrySize += publicArea->dataSize;
8.4.5.17 NvAddEvictObject()
910 TPM_RC
911 NvAddEvictObject(
912 TPMI_DH_OBJECT evictHandle, // IN: new evict handle
913 OBJECT *object // IN: object to be added
914 )
915 {
916 TPM_HANDLE temp = object->evictHandle;
917 TPM_RC result;
918 //
919 // Check if we have enough space to add the evict object
920 // An evict object needs 8 bytes in index table + sizeof OBJECT
921 // In this implementation, the only resource limitation is the available NV
922 // space. Other implementation may have other limitation on evict object
923 // handle space
924 if(!NvTestSpace(sizeof(OBJECT) + sizeof(TPM_HANDLE), FALSE, FALSE))
925 return TPM_RC_NV_SPACE;
926
927 // Set evict attribute and handle
928 object->attributes.evict = SET;
929 object->evictHandle = evictHandle;
930
931 // Now put this in NV
932 result = NvAdd(sizeof(OBJECT), sizeof(OBJECT), evictHandle, (BYTE *)object);
933
8.4.5.18 NvDeleteIndex()
940 TPM_RC
941 NvDeleteIndex(
942 NV_INDEX *nvIndex, // IN: an in RAM index descriptor
943 NV_REF entityAddr // IN: location in NV
944 )
945 {
946 TPM_RC result;
947 //
948 if(nvIndex != NULL)
949 {
950 // Whenever a counter is deleted, make sure that the MaxCounter value is
951 // updated to reflect the value
952 if(IsNvCounterIndex(nvIndex->publicArea.attributes)
953 && IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
954 NvUpdateMaxCount(NvGetUINT64Data(nvIndex, entityAddr));
955 result = NvDelete(entityAddr);
956 if(result != TPM_RC_SUCCESS)
957 return result;
958 // If the NV Index is RAM backed, delete the RAM data as well
959 if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
960 NvDeleteRAM(nvIndex->publicArea.nvIndex);
961 NvIndexCacheInit();
962 }
963 return TPM_RC_SUCCESS;
964 }
8.4.5.19 NvDeleteEvict()
This function will delete a NV evict object. Will return success if object deleted or if it does not exist
965 TPM_RC
966 NvDeleteEvict(
967 TPM_HANDLE handle // IN: handle of entity to be deleted
968 )
969 {
970 NV_REF entityAddr = NvFindEvict(handle, NULL); // pointer to entity
971 TPM_RC result = TPM_RC_SUCCESS;
972 //
973 if(entityAddr != 0)
974 result = NvDelete(entityAddr);
975 return result;
976 }
8.4.5.20 NvFlushHierarchy()
This function will delete persistent objects belonging to the indicated hierarchy. If the storage hierarchy is
selected, the function will also delete any NV Index defined using ownerAuth.
977 TPM_RC
978 NvFlushHierarchy(
979 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed.
980 )
981 {
982 NV_REF iter = NV_REF_INIT;
983 NV_REF currentAddr;
984 TPM_HANDLE entityHandle;
985 TPM_RC result = TPM_RC_SUCCESS;
986 //
987 while((currentAddr = NvNext(&iter, &entityHandle)) != 0)
988 {
989 if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX)
990 {
991 NV_INDEX nvIndex;
992 //
993 // If flush endorsement or platform hierarchy, no NV Index would be
994 // flushed
995 if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM)
996 continue;
997 // Get the index information
998 NvReadNvIndexInfo(currentAddr, &nvIndex);
999
1000 // For storage hierarchy, flush OwnerCreated index
1001 if(!IS_ATTRIBUTE(nvIndex.publicArea.attributes, TPMA_NV,
1002 PLATFORMCREATE))
1003 {
1004 // Delete the index (including RAM for orderly)
1005 result = NvDeleteIndex(&nvIndex, currentAddr);
1006 if(result != TPM_RC_SUCCESS)
1007 break;
1008 // Re-iterate from beginning after a delete
1009 iter = NV_REF_INIT;
1010 }
1011 }
1012 else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT)
1013 {
1014 OBJECT_ATTRIBUTES attributes;
1015 //
1016 NvRead(&attributes,
1017 (UINT32)(currentAddr
1018 + sizeof(TPM_HANDLE)
1019 + offsetof(OBJECT, attributes)),
1020 sizeof(OBJECT_ATTRIBUTES));
1021 // If the evict object belongs to the hierarchy to be flushed...
1022 if((hierarchy == TPM_RH_PLATFORM && attributes.ppsHierarchy == SET)
1023 || (hierarchy == TPM_RH_OWNER && attributes.spsHierarchy == SET)
1024 || (hierarchy == TPM_RH_ENDORSEMENT
1025 && attributes.epsHierarchy == SET))
1026 {
1027 // ...then delete the evict object
1028 result = NvDelete(currentAddr);
1029 if(result != TPM_RC_SUCCESS)
1030 break;
8.4.5.21 NvSetGlobalLock()
This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV indexes that have
TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock().
1042 TPM_RC
1043 NvSetGlobalLock(
1044 void
1045 )
1046 {
1047 NV_REF iter = NV_REF_INIT;
1048 NV_RAM_REF ramIter = NV_RAM_REF_INIT;
1049 NV_REF currentAddr;
1050 NV_RAM_REF currentRamAddr;
1051 TPM_RC result = TPM_RC_SUCCESS;
1052 //
1053 // Check all normal indexes
1054 while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1055 {
1056 TPMA_NV attributes = NvReadNvIndexAttributes(currentAddr);
1057 //
1058 // See if it should be locked
1059 if(!IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1060 && IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1061 {
1062 SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1063 result = NvWriteNvIndexAttributes(currentAddr, attributes);
1064 if(result != TPM_RC_SUCCESS)
1065 return result;
1066 }
1067 }
1068 // Now search all the orderly attributes
1069 while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1070 {
1071 // See if it should be locked
1072 TPMA_NV attributes = NvReadRamIndexAttributes(currentRamAddr);
1073 if(IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1074 {
1075 SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1076 NvWriteRamIndexAttributes(currentRamAddr, attributes);
1077 }
1078 }
1079 return result;
1080 }
8.4.5.22 InsertSort()
Sort a handle into handle list in ascending order. The total handle number in the list should not exceed
MAX_CAP_HANDLES
8.4.5.23 NvCapGetPersistent()
This function is used to get a list of handles of the persistent objects, starting at handle.
Handle must be in valid persistent object handle range, but does not have to reference an existing
persistent object.
1122 TPMI_YES_NO
1123 NvCapGetPersistent(
1124 TPMI_DH_OBJECT handle, // IN: start handle
1125 UINT32 count, // IN: maximum number of returned handles
8.4.5.24 NvCapGetIndex()
This function returns a list of handles of NV indexes, starting from handle. Handle must be in the range of
NV indexes, but does not have to reference an existing NV Index.
1161 TPMI_YES_NO
1162 NvCapGetIndex(
1163 TPMI_DH_OBJECT handle, // IN: start handle
1164 UINT32 count, // IN: max number of returned handles
1165 TPML_HANDLE *handleList // OUT: list of handle
1166 )
1167 {
1168 TPMI_YES_NO more = NO;
1169 NV_REF iter = NV_REF_INIT;
1170 NV_REF currentAddr;
1171 TPM_HANDLE nvHandle;
1172 //
1173 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1174
1175 // Initialize output handle list
1176 handleList->count = 0;
1177
8.4.5.25 NvCapGetIndexNumber()
1200 UINT32
1201 NvCapGetIndexNumber(
1202 void
1203 )
1204 {
1205 UINT32 num = 0;
1206 NV_REF iter = NV_REF_INIT;
1207 //
1208 while(NvNextIndex(NULL, &iter) != 0)
1209 num++;
1210 return num;
1211 }
8.4.5.26 NvCapGetPersistentNumber()
1212 UINT32
1213 NvCapGetPersistentNumber(
1214 void
1215 )
1216 {
1217 UINT32 num = 0;
1218 NV_REF iter = NV_REF_INIT;
1219 TPM_HANDLE handle;
1220 //
1221 while(NvNextEvict(&handle, &iter) != 0)
1222 num++;
1223 return num;
1224 }
8.4.5.27 NvCapGetPersistentAvail()
This function returns an estimate of the number of additional persistent objects that could be loaded into
NV memory.
1225 UINT32
1226 NvCapGetPersistentAvail(
1227 void
1228 )
1229 {
1230 UINT32 availNVSpace;
1231 UINT32 counterNum = NvCapGetCounterNumber();
1232 UINT32 reserved = sizeof(NV_LIST_TERMINATOR);
1233 //
1234 // Get the available space in NV storage
1235 availNVSpace = NvGetFreeBytes();
1236
1237 if(counterNum < MIN_COUNTER_INDICES)
1238 {
1239 // Some space has to be reserved for counter objects.
1240 reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
1241 if(reserved > availNVSpace)
1242 availNVSpace = 0;
1243 else
1244 availNVSpace -= reserved;
1245 }
1246 return availNVSpace / NV_EVICT_OBJECT_SIZE;
1247 }
8.4.5.28 NvCapGetCounterNumber()
1248 UINT32
1249 NvCapGetCounterNumber(
1250 void
1251 )
1252 {
1253 NV_REF iter = NV_REF_INIT;
1254 NV_REF currentAddr;
1255 UINT32 num = 0;
1256 //
1257 while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1258 {
1259 TPMA_NV attributes = NvReadNvIndexAttributes(currentAddr);
1260 if(IsNvCounterIndex(attributes))
1261 num++;
1262 }
1263 return num;
1264 }
8.4.5.29 NvSetStartupAttributes()
Local function to set the attributes of an Index at TPM Reset and TPM Restart.
8.4.5.30 NvEntityStartup()
This function is called at TPM_Startup(). If the startup completes a TPM Resume cycle, no action is
taken. If the startup is a TPM Reset or a TPM Restart, then this function will:
clear read/write lock;
reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and
set the lower bits in orderly counters to 1 for a non-orderly startup
It is a prerequisite that NV be available for writing before this function is called.
1291 BOOL
1292 NvEntityStartup(
1293 STARTUP_TYPE type // IN: start up type
1294 )
1295 {
1296 NV_REF iter = NV_REF_INIT;
1297 NV_RAM_REF ramIter = NV_RAM_REF_INIT;
1298 NV_REF currentAddr; // offset points to the current entity
1299 NV_RAM_REF currentRamAddr;
1300 TPM_HANDLE nvHandle;
1301 TPMA_NV attributes;
1302 //
1303 // Restore RAM index data
1304 NvRead(s_indexOrderlyRam, NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam));
1305
1306 // Initialize the max NV counter value
1307 NvSetMaxCount(NvGetMaxCount());
1308
1309 // If recovering from state save, do nothing else
1310 if(type == SU_RESUME)
1311 return TRUE;
1312 // Iterate all the NV Index to clear the locks
1313 while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1314 {
1315 attributes = NvReadNvIndexAttributes(currentAddr);
1316
1317 // If this is an orderly index, defer processing until loop below
1318 if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
1319 continue;
1320 // Set the attributes appropriate for this startup type
1321 attributes = NvSetStartupAttributes(attributes, type);
1322 NvWriteNvIndexAttributes(currentAddr, attributes);
1323 }
1324 // Iterate all the orderly indexes to clear the locks and initialize counters
1325 while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1326 {
1327 attributes = NvReadRamIndexAttributes(currentRamAddr);
1328
1329 attributes = NvSetStartupAttributes(attributes, type);
1330
1331 // update attributes in RAM
1332 NvWriteRamIndexAttributes(currentRamAddr, attributes);
1333
1334 // Set the lower bits in an orderly counter to 1 for a non-orderly startup
1335 if(IsNvCounterIndex(attributes)
1336 && (g_prevOrderlyState == SU_NONE_VALUE))
1337 {
1338 UINT64 counter;
1339 //
1340 // Read the counter value last saved to NV.
1341 counter = BYTE_ARRAY_TO_UINT64(currentRamAddr + sizeof(NV_RAM_HEADER));
1342
1343 // Set the lower bits of counter to 1's
1344 counter |= MAX_ORDERLY_COUNT;
1345
1346 // Write back to RAM
1347 // NOTE: Do not want to force a write to NV here. The counter value will
1348 // stay in RAM until the next shutdown or rollover.
1349 UINT64_TO_BYTE_ARRAY(counter, currentRamAddr + sizeof(NV_RAM_HEADER));
1350 }
1351 }
1352 return TRUE;
1353 }
8.4.5.31 NvCapGetCounterAvail()
This function returns an estimate of the number of additional counter type NV indexes that can be
defined.
1354 UINT32
1355 NvCapGetCounterAvail(
1356 void
1357 )
1358 {
1359 UINT32 availNVSpace;
1360 UINT32 availRAMSpace;
1361 UINT32 persistentNum = NvCapGetPersistentNumber();
1362 UINT32 reserved = sizeof(NV_LIST_TERMINATOR);
1363 //
1364 // Get the available space in NV storage
1365 availNVSpace = NvGetFreeBytes();
1366
1367 if(persistentNum < MIN_EVICT_OBJECTS)
1368 {
1369 // Some space has to be reserved for evict object. Adjust availNVSpace.
1370 reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
1371 if(reserved > availNVSpace)
1372 availNVSpace = 0;
1373 else
1374 availNVSpace -= reserved;
1375 }
1376 // Compute the available space in RAM
1377 availRAMSpace = (int)(RAM_ORDERLY_END - NvRamGetEnd());
1378
1379 // Return the min of counter number in NV and in RAM
1380 if(availNVSpace / NV_INDEX_COUNTER_SIZE
8.4.5.32 NvFindHandle()
this function returns the offset in NV memory of the entity associated with the input handle. A value of
zero indicates that handle does not exist reference an existing persistent object or defined NV Index.
1386 NV_REF
1387 NvFindHandle(
1388 TPM_HANDLE handle
1389 )
1390 {
1391 NV_REF addr;
1392 NV_REF iter = NV_REF_INIT;
1393 TPM_HANDLE nextHandle;
1394 //
1395 while((addr = NvNext(&iter, &nextHandle)) != 0)
1396 {
1397 if(nextHandle == handle)
1398 break;
1399 }
1400 return addr;
1401 }
8.4.6.1 Introduction
The TPM keeps track of the highest value of a deleted counter index. When an index is deleted, this
value is updated if the deleted counter index is greater than the previous value. When a new index is
created and first incremented, it will get a value that is at least one greater than any other index than any
previously deleted index. This insures that it is not possible to roll back an index.
The highest counter value is keep in NV in a special end-of-list marker. This marker is only updated when
an index is deleted. Otherwise it just moves.
When the TPM starts up, it searches NV for the end of list marker and initializes an in memory value
(s_maxCounter).
8.4.6.2 NvReadMaxCount()
1402 UINT64
1403 NvReadMaxCount(
1404 void
1405 )
1406 {
1407 return s_maxCounter;
1408 }
8.4.6.3 NvUpdateMaxCount()
This function updates the max counter value to NV memory. This is just staging for the actual write that
will occur when the NV index memory is modified.
1409 void
1410 NvUpdateMaxCount(
1411 UINT64 count
1412 )
1413 {
1414 if(count > s_maxCounter)
1415 s_maxCounter = count;
1416 }
8.4.6.4 NvSetMaxCount()
This function is used at NV initialization time to set the initial value of the maximum counter.
1417 void
1418 NvSetMaxCount(
1419 UINT64 value
1420 )
1421 {
1422 s_maxCounter = value;
1423 }
8.4.6.5 NvGetMaxCount()
Function to get the NV max counter value from the end-of-list marker
1424 UINT64
1425 NvGetMaxCount(
1426 void
1427 )
1428 {
1429 NV_REF iter = NV_REF_INIT;
1430 NV_REF currentAddr;
1431 UINT64 maxCount;
1432 //
1433 // Find the end of list marker and initialize the NV Max Counter value.
1434 while((currentAddr = NvNext(&iter, NULL )) != 0);
1435 // 'iter' should be pointing at the end of list marker so read in the current
1436 // value of the s_maxCounter.
1437 NvRead(&maxCount, iter + sizeof(UINT32), sizeof(maxCount));
1438
1439 return maxCount;
1440 }
8.5 NvReserved.c
8.5.1 Introduction
The NV memory is divided into two areas: dynamic space for user defined NV Indices and evict objects,
and reserved space for TPM persistent and state save data.
The entries in dynamic space are a linked list of entries. Each entry has, as its first field, a size. If the size
field is zero, it marks the end of the list.
An allocation of an Index or evict object may use almost all of the remaining NV space such that the size
field will not fit. The functions that search the list are aware of this and will terminate the search if they
either find a zero size or recognize that there is insufficient space for the size field.
An Index allocation will contain an NV_INDEX structure. If the Index does not have the orderly attribute,
the NV_INDEX is followed immediately by the NV data.
An evict object entry contains a handle followed by an OBJECT structure. This results in both the Index
and Evict Object having an identifying handle as the first field following the size field.
When an Index has the orderly attribute, the data is kept in RAM. This RAM is saved to backing store in
NV memory on any orderly shutdown. The entries in orderly memory are also a linked list using a size
field as the first entry. As with the NV memory, the list is terminated by a zero size field or when the last
entry leaves insufficient space for the terminating size field.
The attributes of an orderly index are maintained in RAM memory in order to reduce the number of NV
writes needed for orderly data. When an orderly index is created, an entry is made in the dynamic NV
memory space that holds the Index authorizations (authPolicy and authValue) and the size of the data.
This entry is only modified if the authValue of the index is changed. The more volatile data of the index is
kept in RAM. When an orderly Index is created or deleted, the RAM data is copied to NV backing store so
that the image in the backing store matches the layout of RAM. In normal operation. The RAM data is
also copied on any orderly shutdown. In normal operation, the only other reason for writing to the backing
store for RAM is when a counter is first written (TPMA_NV_WRITTEN changes from CLEAR to SET) or
when a counter "rolls over."
Static space contains items that are individually modifiable. The values are in the gp
PERSISTEND_DATA structure in RAM and mapped to locations in NV.
1 #define NV_C
2 #include "Tpm.h"
8.5.3 Functions
8.5.3.1 NvInitStatic()
3 static void
4 NvInitStatic(
5 void
6 )
7 {
8 // In some implementations, the end of NV is variable and is set at boot time.
9 // This value will be the same for each boot, but is not necessarily known
10 // at compile time.
11 s_evictNvEnd = (NV_REF)NV_MEMORY_SIZE;
12 return;
13 }
8.5.3.2 NvCheckState()
Function to check the NV state by accessing the platform-specific function to get the NV state. The result
state is registered in s_NvIsAvailable that will be reported by NvIsAvailable().
This function is called at the beginning of ExecuteCommand() before any potential check of g_NvStatus.
14 void
15 NvCheckState(
16 void
17 )
18 {
19 int func_return;
20 //
21 func_return = _plat__IsNvAvailable();
22 if(func_return == 0)
23 g_NvStatus = TPM_RC_SUCCESS;
24 else if(func_return == 1)
25 g_NvStatus = TPM_RC_NV_UNAVAILABLE;
26 else
27 g_NvStatus = TPM_RC_NV_RATE;
28 return;
29 }
8.5.3.3 NvCommit
30 BOOL
31 NvCommit(
32 void
33 )
34 {
35 return (_plat__NvCommit() == 0);
36 }
8.5.3.4 NvPowerOn()
37 BOOL
38 NvPowerOn(
39 void
40 )
41 {
42 int nvError = 0;
43 // If power was lost, need to re-establish the RAM data that is loaded from
44 // NV and initialize the static variables
45 if(g_powerWasLost)
46 {
47 if((nvError = _plat__NVEnable(0)) < 0)
48 FAIL(FATAL_ERROR_NV_UNRECOVERABLE);
49 NvInitStatic();
50 }
51 return nvError == 0;
52 }
8.5.3.5 NvManufacture()
53 void
54 NvManufacture(
55 void
56 )
57 {
58 #if SIMULATION
59 // Simulate the NV memory being in the erased state.
60 _plat__NvMemoryClear(0, NV_MEMORY_SIZE);
61 #endif
62 // Initialize static variables
63 NvInitStatic();
64 // Clear the RAM used for Orderly Index data
65 MemorySet(s_indexOrderlyRam, 0, RAM_INDEX_SPACE);
66 // Write that Orderly Index data to NV
67 NvUpdateIndexOrderlyData();
68 // Initialize the next offset of the first entry in evict/index list to 0 (the
69 // end of list marker) and the initial s_maxCounterValue;
70 NvSetMaxCount(0);
71 // Put the end of list marker at the end of memory. This contains the MaxCount
72 // value as well as the end marker.
73 NvWriteNvListEnd(NV_USER_DYNAMIC);
74 return;
75 }
8.5.3.6 NvRead()
76 void
77 NvRead(
78 void *outBuffer, // OUT: buffer to receive data
79 UINT32 nvOffset, // IN: offset in NV of value
80 UINT32 size // IN: size of the value to read
81 )
82 {
83 // Input type should be valid
84 pAssert(nvOffset + size < NV_MEMORY_SIZE);
85 _plat__NvMemoryRead(nvOffset, size, outBuffer);
86 return;
87 }
8.5.3.7 NvWrite()
This function is used to post reserved data for writing to NV memory. Before the TPM completes the
operation, the value will be written.
88 BOOL
89 NvWrite(
90 UINT32 nvOffset, // IN: location in NV to receive data
8.5.3.8 NvUpdatePersistent()
This function is used to update a value in the PERSISTENT_DATA structure and commits the value to
NV.
104 void
105 NvUpdatePersistent(
106 UINT32 offset, // IN: location in PERMANENT_DATA to be updated
107 UINT32 size, // IN: size of the value
108 void *buffer // IN: the new data
109 )
110 {
111 pAssert(offset + size <= sizeof(gp));
112 MemoryCopy(&gp + offset, buffer, size);
113 NvWrite(offset, size, buffer);
114 }
8.5.3.9 NvClearPersistent()
115 void
116 NvClearPersistent(
117 UINT32 offset, // IN: the offset in the PERMANENT_DATA
118 // structure to be cleared (zeroed)
119 UINT32 size // IN: number of bytes to clear
120 )
121 {
122 pAssert(offset + size <= sizeof(gp));
123 MemorySet((&gp) + offset, 0, size);
124 NvWrite(offset, size, (&gp) + offset);
125 }
8.5.3.10 NvReadPersistent()
This function reads persistent data to the RAM copy of the gp structure.
126 void
127 NvReadPersistent(
128 void
129 )
130 {
131 NvRead(&gp, NV_PERSISTENT_DATA, sizeof(gp));
132 return;
133 }
8.6 Object.c
8.6.1 Introduction
This file contains the functions that manage the object store of the TPM.
1 #define OBJECT_C
2 #include "Tpm.h"
8.6.3 Functions
8.6.3.1 ObjectFlush()
This function marks an object slot as available. Since there is no checking of the input parameters, it
should be used judiciously.
3 void
4 ObjectFlush(
5 OBJECT *object
6 )
7 {
8 object->attributes.occupied = CLEAR;
9 }
8.6.3.2 ObjectSetInUse()
10 void
11 ObjectSetInUse(
12 OBJECT *object
13 )
14 {
15 object->attributes.occupied = SET;
16 }
8.6.3.3 ObjectStartup()
17 BOOL
18 ObjectStartup(
19 void
20 )
21 {
22 UINT32 i;
23 //
24 // object slots initialization
25 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
26 {
27 //Set the slot to not occupied
28 ObjectFlush(&s_objects[i]);
29 }
30 return TRUE;
31 }
8.6.3.4 ObjectCleanupEvict()
In this implementation, a persistent object is moved from NV into an object slot for processing. It is
flushed after command execution. This function is called from ExecuteCommand().
32 void
33 ObjectCleanupEvict(
34 void
35 )
36 {
37 UINT32 i;
38 //
39 // This has to be iterated because a command may have two handles
40 // and they may both be persistent.
41 // This could be made to be more efficient so that a search is not needed.
42 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
43 {
44 // If an object is a temporary evict object, flush it from slot
45 OBJECT *object = &s_objects[i];
46 if(object->attributes.evict == SET)
47 ObjectFlush(object);
48 }
49 return;
50 }
8.6.3.5 IsObjectPresent()
This function checks to see if a transient handle references a loaded object. This routine should not be
called if the handle is not a transient handle. The function validates that the handle is in the
implementation-dependent allowed in range for loaded transient objects.
51 BOOL
52 IsObjectPresent(
53 TPMI_DH_OBJECT handle // IN: handle to be checked
54 )
55 {
56 UINT32 slotIndex = handle - TRANSIENT_FIRST;
57 // Since the handle is just an index into the array that is zero based, any
58 // handle value outsize of the range of:
59 // TRANSIENT_FIRST -- (TRANSIENT_FIRST + MAX_LOADED_OBJECT - 1)
60 // will now be greater than or equal to MAX_LOADED_OBJECTS
61 if(slotIndex >= MAX_LOADED_OBJECTS)
62 return FALSE;
63 // Indicate if the slot is occupied
64 return (s_objects[slotIndex].attributes.occupied == TRUE);
65 }
8.6.3.6 ObjectIsSequence()
This function is used to check if the object is a sequence object. This function should not be called if the
handle does not reference a loaded object.
66 BOOL
67 ObjectIsSequence(
68 OBJECT *object // IN: handle to be checked
69 )
70 {
71 pAssert(object != NULL);
72 return (object->attributes.hmacSeq == SET
73 || object->attributes.hashSeq == SET
74 || object->attributes.eventSeq == SET);
75 }
8.6.3.7 HandleToObject()
This function is used to find the object structure associated with a handle.
This function requires that handle references a loaded object or a permanent handle.
76 OBJECT*
77 HandleToObject(
78 TPMI_DH_OBJECT handle // IN: handle of the object
79 )
80 {
81 UINT32 index;
82 //
83 // Return NULL if the handle references a permanent handle because there is no
84 // associated OBJECT.
85 if(HandleGetType(handle) == TPM_HT_PERMANENT)
86 return NULL;
87 // In this implementation, the handle is determined by the slot occupied by the
88 // object.
89 index = handle - TRANSIENT_FIRST;
90 pAssert(index < MAX_LOADED_OBJECTS);
91 pAssert(s_objects[index].attributes.occupied);
92 return &s_objects[index];
93 }
8.6.3.8 GetQualifiedName()
This function returns the Qualified Name of the object. In this implementation, the Qualified Name is
computed when the object is loaded and is saved in the internal representation of the object. The
alternative would be to retain the Name of the parent and compute the QN when needed. This would take
the same amount of space so it is not recommended that the alternate be used.
This function requires that handle references a loaded object.
94 void
95 GetQualifiedName(
96 TPMI_DH_OBJECT handle, // IN: handle of the object
97 TPM2B_NAME *qualifiedName // OUT: qualified name of the object
98 )
99 {
100 OBJECT *object;
101 //
102 switch(HandleGetType(handle))
103 {
104 case TPM_HT_PERMANENT:
8.6.3.9 ObjectGetHierarchy()
121 TPMI_RH_HIERARCHY
122 ObjectGetHierarchy(
123 OBJECT *object // IN :object
124 )
125 {
126 if(object->attributes.spsHierarchy)
127 {
128 return TPM_RH_OWNER;
129 }
130 else if(object->attributes.epsHierarchy)
131 {
132 return TPM_RH_ENDORSEMENT;
133 }
134 else if(object->attributes.ppsHierarchy)
135 {
136 return TPM_RH_PLATFORM;
137 }
138 else
139 {
140 return TPM_RH_NULL;
141 }
142 }
8.6.3.10 GetHeriarchy()
This function returns the handle of the hierarchy to which a handle belongs. This function is similar to
ObjectGetHierarchy() but this routine takes a handle while ObjectGetHierarchy() takes an pointer to an
object.
This function requires that handle references a loaded object.
143 TPMI_RH_HIERARCHY
144 GetHeriarchy(
145 TPMI_DH_OBJECT handle // IN :object handle
146 )
147 {
148 OBJECT *object = HandleToObject(handle);
149 //
150 return ObjectGetHierarchy(object);
151 }
8.6.3.11 FindEmptyObjectSlot()
This function finds an open object slot, if any. It will clear the attributes but will not set the occupied
attribute. This is so that a slot may be used and discarded if everything does not go as planned.
152 OBJECT *
153 FindEmptyObjectSlot(
154 TPMI_DH_OBJECT *handle // OUT: (optional)
155 )
156 {
157 UINT32 i;
158 OBJECT *object;
159 //
160 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
161 {
162 object = &s_objects[i];
163 if(object->attributes.occupied == CLEAR)
164 {
165 if(handle)
166 *handle = i + TRANSIENT_FIRST;
167 // Initialize the object attributes
168 MemorySet(&object->attributes, 0, sizeof(OBJECT_ATTRIBUTES));
169 return object;
170 }
171 }
172 return NULL;
173 }
8.6.3.12 ObjectAllocateSlot()
174 OBJECT *
175 ObjectAllocateSlot(
176 TPMI_DH_OBJECT *handle // OUT: handle of allocated object
177 )
178 {
179 OBJECT *object = FindEmptyObjectSlot(handle);
180 //
181 if(object != NULL)
182 {
183 // if found, mark as occupied
184 ObjectSetInUse(object);
185 }
186 return object;
187 }
8.6.3.13 ObjectSetLoadedAttributes()
This function sets the internal attributes for a loaded object. It is called to finalize the OBJECT attributes
(not the TPMA_OBJECT attributes) for a loaded object.
188 void
189 ObjectSetLoadedAttributes(
190 OBJECT *object, // IN: object attributes to finalize
191 TPM_HANDLE parentHandle // IN: the parent handle
192 )
193 {
194 OBJECT *parent = HandleToObject(parentHandle);
195 TPMA_OBJECT objectAttributes = object->publicArea.objectAttributes;
196 //
197 // Copy the stClear attribute from the public area. This could be overwritten
198 // if the parent has stClear SET
199 object->attributes.stClear =
200 IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear);
201 // If parent handle is a permanent handle, it is a primary (unless it is NULL
202 if(parent == NULL)
203 {
204 object->attributes.primary = SET;
205 switch(parentHandle)
206 {
207 case TPM_RH_ENDORSEMENT:
208 object->attributes.epsHierarchy = SET;
209 break;
210 case TPM_RH_OWNER:
211 object->attributes.spsHierarchy = SET;
212 break;
213 case TPM_RH_PLATFORM:
214 object->attributes.ppsHierarchy = SET;
215 break;
216 default:
217 // Treat the temporary attribute as a hierarchy
218 object->attributes.temporary = SET;
219 object->attributes.primary = CLEAR;
220 break;
221 }
222 }
223 else
224 {
225 // is this a stClear object
226 object->attributes.stClear =
227 (IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear)
228 || (parent->attributes.stClear == SET));
229 object->attributes.epsHierarchy = parent->attributes.epsHierarchy;
230 object->attributes.spsHierarchy = parent->attributes.spsHierarchy;
231 object->attributes.ppsHierarchy = parent->attributes.ppsHierarchy;
232 // An object is temporary if its parent is temporary or if the object
233 // is external
234 object->attributes.temporary = parent->attributes.temporary
235 || object->attributes.external;
236 }
237 // If this is an external object, set the QN == name but don't SET other
238 // key properties ('parent' or 'derived')
239 if(object->attributes.external)
240 object->qualifiedName = object->name;
241 else
242 {
243 // check attributes for different types of parents
244 if(IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, restricted)
245 && !object->attributes.publicOnly
246 && IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, decrypt)
247 && object->publicArea.nameAlg != TPM_ALG_NULL)
248 {
249 // This is a parent. If it is not a KEYEDHASH, it is an ordinary parent.
250 // Otherwise, it is a derivation parent.
251 if(object->publicArea.type == TPM_ALG_KEYEDHASH)
252 object->attributes.derivation = SET;
253 else
254 object->attributes.isParent = SET;
255 }
256 ComputeQualifiedName(parentHandle, object->publicArea.nameAlg,
257 &object->name, &object->qualifiedName);
258 }
259 // Set slot occupied
260 ObjectSetInUse(object);
261 return;
262 }
8.6.3.14 ObjectLoad()
Common function to load an object. A loaded object has its public area validated (unless its nameAlg is
TPM_ALG_NULL). If a sensitive part is loaded, it is verified to be correct and if both public and sensitive
parts are loaded, then the cryptographic binding between the objects is validated. This function does not
cause the allocated slot to be marked as in use.
263 TPM_RC
264 ObjectLoad(
265 OBJECT *object, // IN: pointer to object slot
266 // object
267 OBJECT *parent, // IN: (optional) the parent object
268 TPMT_PUBLIC *publicArea, // IN: public area to be installed in the object
269 TPMT_SENSITIVE *sensitive, // IN: (optional) sensitive area to be
270 // installed in the object
271 TPM_RC blamePublic, // IN: parameter number to associate with the
272 // publicArea errors
273 TPM_RC blameSensitive,// IN: parameter number to associate with the
274 // sensitive area errors
275 TPM2B_NAME *name // IN: (optional)
276 )
277 {
278 TPM_RC result = TPM_RC_SUCCESS;
279 //
280 // Do validations of public area object descriptions
281 pAssert(publicArea != NULL);
282
283 // Is this public only or a no-name object?
284 if(sensitive == NULL || publicArea->nameAlg == TPM_ALG_NULL)
285 {
286 // Need to have schemes checked so that we do the right thing with the
287 // public key.
288 result = SchemeChecks(NULL, publicArea);
289 }
290 else
291 {
292 // For any sensitive area, make sure that the seedSize is no larger than the
293 // digest size of nameAlg
294 if(sensitive->seedValue.t.size > CryptHashGetDigestSize(publicArea->nameAlg))
295 return TPM_RCS_KEY_SIZE + blameSensitive;
296 // Check attributes and schemes for consistency
297 result = PublicAttributesValidation(parent, publicArea);
298 }
299 if(result != TPM_RC_SUCCESS)
300 return RcSafeAddToResult(result, blamePublic);
301
302 // Sensitive area and binding checks
303
304 // On load, check nothing if the parent is fixedTPM. For all other cases, validate
305 // the keys.
306 if((parent == NULL)
307 || ((parent != NULL) && !IS_ATTRIBUTE(parent->publicArea.objectAttributes,
308 TPMA_OBJECT, fixedTPM)))
309 {
310 // Do the cryptographic key validation
311 result = CryptValidateKeys(publicArea, sensitive, blamePublic,
312 blameSensitive);
313 if(result != TPM_RC_SUCCESS)
8.6.3.15 AllocateSequenceSlot()
This function allocates a sequence slot and initializes the parts that are used by the normal objects so
that a sequence object is not inadvertently used for an operation that is not appropriate for a sequence.
8.6.3.16 ObjectCreateHMACSequence()
388 TPM_RC
389 ObjectCreateHMACSequence(
390 TPMI_ALG_HASH hashAlg, // IN: hash algorithm
391 OBJECT *keyObject, // IN: the object containing the HMAC key
392 TPM2B_AUTH *auth, // IN: authValue
393 TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle
394 )
395 {
396 HASH_OBJECT *hmacObject;
397 //
398 // Try to allocate a slot for new object
399 hmacObject = AllocateSequenceSlot(newHandle, auth);
400
401 if(hmacObject == NULL)
402 return TPM_RC_OBJECT_MEMORY;
403 // Set HMAC sequence bit
404 hmacObject->attributes.hmacSeq = SET;
405
406 #if !SMAC_IMPLEMENTED
407 if(CryptHmacStart(&hmacObject->state.hmacState, hashAlg,
408 keyObject->sensitive.sensitive.bits.b.size,
409 keyObject->sensitive.sensitive.bits.b.buffer) == 0)
410 #else
411 if(CryptMacStart(&hmacObject->state.hmacState,
412 &keyObject->publicArea.parameters,
413 hashAlg, &keyObject->sensitive.sensitive.any.b) == 0)
414 #endif // SMAC_IMPLEMENTED
415 return TPM_RC_FAILURE;
416 return TPM_RC_SUCCESS;
417 }
418 #endif
8.6.3.17 ObjectCreateHashSequence()
419 TPM_RC
420 ObjectCreateHashSequence(
421 TPMI_ALG_HASH hashAlg, // IN: hash algorithm
422 TPM2B_AUTH *auth, // IN: authValue
423 TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
424 )
425 {
426 HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth);
427 //
428 // See if slot allocated
429 if(hashObject == NULL)
430 return TPM_RC_OBJECT_MEMORY;
431 // Set hash sequence bit
432 hashObject->attributes.hashSeq = SET;
433
434 // Start hash for hash sequence
435 CryptHashStart(&hashObject->state.hashState[0], hashAlg);
436
437 return TPM_RC_SUCCESS;
438 }
8.6.3.18 ObjectCreateEventSequence()
439 TPM_RC
440 ObjectCreateEventSequence(
441 TPM2B_AUTH *auth, // IN: authValue
442 TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
443 )
444 {
445 HASH_OBJECT *hashObject = AllocateSequenceSlot(newHandle, auth);
446 UINT32 count;
447 TPM_ALG_ID hash;
448 //
449 // See if slot allocated
450 if(hashObject == NULL)
451 return TPM_RC_OBJECT_MEMORY;
452 // Set the event sequence attribute
453 hashObject->attributes.eventSeq = SET;
454
455 // Initialize hash states for each implemented PCR algorithms
456 for(count = 0; (hash = CryptHashGetAlgByIndex(count)) != TPM_ALG_NULL; count++)
457 CryptHashStart(&hashObject->state.hashState[count], hash);
458 return TPM_RC_SUCCESS;
459 }
8.6.3.19 ObjectTerminateEvent()
This function is called to close out the event sequence and clean up the hash context states.
460 void
461 ObjectTerminateEvent(
462 void
463 )
464 {
465 HASH_OBJECT *hashObject;
466 int count;
467 BYTE buffer[MAX_DIGEST_SIZE];
468 //
469 hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle);
470
471 // Don't assume that this is a proper sequence object
472 if(hashObject->attributes.eventSeq)
473 {
474 // If it is, close any open hash contexts. This is done in case
475 // the cryptographic implementation has some context values that need to be
476 // cleaned up (hygiene).
477 //
478 for(count = 0; CryptHashGetAlgByIndex(count) != TPM_ALG_NULL; count++)
479 {
480 CryptHashEnd(&hashObject->state.hashState[count], 0, buffer);
481 }
482 // Flush sequence object
483 FlushObject(g_DRTMHandle);
484 }
485 g_DRTMHandle = TPM_RH_UNASSIGNED;
486 }
8.6.3.20 ObjectContextLoad()
487 OBJECT *
488 ObjectContextLoad(
489 ANY_OBJECT_BUFFER *object, // IN: pointer to object structure in saved
490 // context
491 TPMI_DH_OBJECT *handle // OUT: object handle
492 )
493 {
494 OBJECT *newObject = ObjectAllocateSlot(handle);
495 //
496 // Try to allocate a slot for new object
497 if(newObject != NULL)
498 {
499 // Copy the first part of the object
500 MemoryCopy(newObject, object, offsetof(HASH_OBJECT, state));
501 // See if this is a sequence object
502 if(ObjectIsSequence(newObject))
503 {
504 // If this is a sequence object, import the data
505 SequenceDataImport((HASH_OBJECT *)newObject,
506 (HASH_OBJECT_BUFFER *)object);
507 }
508 else
509 {
510 // Copy input object data to internal structure
511 MemoryCopy(newObject, object, sizeof(OBJECT));
512 }
513 }
514 return newObject;
515 }
8.6.3.21 FlushObject()
516 void
517 FlushObject(
518 TPMI_DH_OBJECT handle // IN: handle to be freed
519 )
520 {
521 UINT32 index = handle - TRANSIENT_FIRST;
522 //
523 pAssert(index < MAX_LOADED_OBJECTS);
524 // Clear all the object attributes
525 MemorySet((BYTE*)&(s_objects[index].attributes),
526 0, sizeof(OBJECT_ATTRIBUTES));
527 return;
528 }
8.6.3.22 ObjectFlushHierarchy()
This function is called to flush all the loaded transient objects associated with a hierarchy when the
hierarchy is disabled.
529 void
530 ObjectFlushHierarchy(
531 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush
532 )
533 {
534 UINT16 i;
535 //
536 // iterate object slots
537 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
538 {
539 if(s_objects[i].attributes.occupied) // If found an occupied slot
540 {
541 switch(hierarchy)
542 {
543 case TPM_RH_PLATFORM:
544 if(s_objects[i].attributes.ppsHierarchy == SET)
545 s_objects[i].attributes.occupied = FALSE;
546 break;
547 case TPM_RH_OWNER:
548 if(s_objects[i].attributes.spsHierarchy == SET)
549 s_objects[i].attributes.occupied = FALSE;
550 break;
551 case TPM_RH_ENDORSEMENT:
552 if(s_objects[i].attributes.epsHierarchy == SET)
553 s_objects[i].attributes.occupied = FALSE;
554 break;
555 default:
556 FAIL(FATAL_ERROR_INTERNAL);
557 break;
558 }
559 }
560 }
561
562 return;
563 }
8.6.3.23 ObjectLoadEvict()
564 TPM_RC
565 ObjectLoadEvict(
566 TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it
567 // will be replace by the loaded object handle
568 COMMAND_INDEX commandIndex // IN: the command being processed
569 )
570 {
571 TPM_RC result;
572 TPM_HANDLE evictHandle = *handle; // Save the evict handle
573 OBJECT *object;
574 //
575 // If this is an index that references a persistent object created by
576 // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE
577 if(*handle >= PLATFORM_PERSISTENT)
578 {
579 // belongs to platform
580 if(g_phEnable == CLEAR)
581 return TPM_RC_HANDLE;
582 }
583 // belongs to owner
584 else if(gc.shEnable == CLEAR)
585 return TPM_RC_HANDLE;
586 // Try to allocate a slot for an object
587 object = ObjectAllocateSlot(handle);
588 if(object == NULL)
589 return TPM_RC_OBJECT_MEMORY;
590 // Copy persistent object to transient object slot. A TPM_RC_HANDLE
591 // may be returned at this point. This will mark the slot as containing
592 // a transient object so that it will be flushed at the end of the
593 // command
594 result = NvGetEvictObject(evictHandle, object);
595
596 // Bail out if this failed
597 if(result != TPM_RC_SUCCESS)
598 return result;
599 // check the object to see if it is in the endorsement hierarchy
600 // if it is and this is not a TPM2_EvictControl() command, indicate
601 // that the hierarchy is disabled.
602 // If the associated hierarchy is disabled, make it look like the
603 // handle is not defined
604 if(ObjectGetHierarchy(object) == TPM_RH_ENDORSEMENT
605 && gc.ehEnable == CLEAR
606 && GetCommandCode(commandIndex) != TPM_CC_EvictControl)
607 return TPM_RC_HANDLE;
608
609 return result;
610 }
8.6.3.24 ObjectComputeName()
This does the name computation from a public area (can be marshaled or not).
611 TPM2B_NAME *
612 ObjectComputeName(
613 UINT32 size, // IN: the size of the area to digest
614 BYTE *publicArea, // IN: the public area to digest
615 TPM_ALG_ID nameAlg, // IN: the hash algorithm to use
616 TPM2B_NAME *name // OUT: Computed name
617 )
618 {
619 // Hash the publicArea into the name buffer leaving room for the nameAlg
620 name->t.size = CryptHashBlock(nameAlg, size, publicArea,
621 sizeof(name->t.name) - 2,
622 &name->t.name[2]);
623 // set the nameAlg
624 UINT16_TO_BYTE_ARRAY(nameAlg, name->t.name);
625 name->t.size += 2;
626 return name;
627 }
8.6.3.25 PublicMarshalAndComputeName()
This function computes the Name of an object from its public area.
628 TPM2B_NAME *
629 PublicMarshalAndComputeName(
630 TPMT_PUBLIC *publicArea, // IN: public area of an object
631 TPM2B_NAME *name // OUT: name of the object
632 )
633 {
634 // Will marshal a public area into a template. This is because the internal
635 // format for a TPM2B_PUBLIC is a structure and not a simple BYTE buffer.
636 TPM2B_TEMPLATE marshaled; // this is big enough to hold a
637 // marshaled TPMT_PUBLIC
638 BYTE *buffer = (BYTE *)&marshaled.t.buffer;
639 //
640 // if the nameAlg is NULL then there is no name.
641 if(publicArea->nameAlg == TPM_ALG_NULL)
642 name->t.size = 0;
643 else
644 {
645 // Marshal the public area into its canonical form
646 marshaled.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, NULL);
647 // and compute the name
648 ObjectComputeName(marshaled.t.size, marshaled.t.buffer,
649 publicArea->nameAlg, name);
650 }
651 return name;
652 }
8.6.3.26 ComputeQualifiedName()
653 void
654 ComputeQualifiedName(
655 TPM_HANDLE parentHandle, // IN: parent's handle
656 TPM_ALG_ID nameAlg, // IN: name hash
657 TPM2B_NAME *name, // IN: name of the object
658 TPM2B_NAME *qualifiedName // OUT: qualified name of the object
659 )
660 {
661 HASH_STATE hashState; // hash state
662 TPM2B_NAME parentName;
663 //
8.6.3.27 ObjectIsStorage()
This function determines if an object has the attributes associated with a parent. A parent is an
asymmetric or symmetric block cipher key that has its restricted and decrypt attributes SET, and sign
CLEAR.
692 BOOL
693 ObjectIsStorage(
694 TPMI_DH_OBJECT handle // IN: object handle
695 )
696 {
697 OBJECT *object = HandleToObject(handle);
698 TPMT_PUBLIC *publicArea = ((object != NULL) ? &object->publicArea : NULL);
699 //
700 return (publicArea != NULL
701 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
702 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
703 && !IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)
704 && (object->publicArea.type == ALG_RSA_VALUE
705 || object->publicArea.type == ALG_ECC_VALUE));
706 }
8.6.3.28 ObjectCapGetLoaded()
This function returns a a list of handles of loaded object, starting from handle. Handle must be in the
range of valid transient object handles, but does not have to be the handle of a loaded transient object.
707 TPMI_YES_NO
708 ObjectCapGetLoaded(
709 TPMI_DH_OBJECT handle, // IN: start handle
710 UINT32 count, // IN: count of returned handles
711 TPML_HANDLE *handleList // OUT: list of handle
712 )
713 {
714 TPMI_YES_NO more = NO;
715 UINT32 i;
716 //
717 pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
718
719 // Initialize output handle list
720 handleList->count = 0;
721
722 // The maximum count of handles we may return is MAX_CAP_HANDLES
723 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
724
725 // Iterate object slots to get loaded object handles
726 for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++)
727 {
728 if(s_objects[i].attributes.occupied == TRUE)
729 {
730 // A valid transient object can not be the copy of a persistent object
731 pAssert(s_objects[i].attributes.evict == CLEAR);
732
733 if(handleList->count < count)
734 {
735 // If we have not filled up the return list, add this object
736 // handle to it
737 handleList->handle[handleList->count] = i + TRANSIENT_FIRST;
738 handleList->count++;
739 }
740 else
741 {
742 // If the return list is full but we still have loaded object
743 // available, report this and stop iterating
744 more = YES;
745 break;
746 }
747 }
748 }
749
750 return more;
751 }
8.6.3.29 ObjectCapGetTransientAvail()
This function returns an estimate of the number of additional transient objects that could be loaded into
the TPM.
752 UINT32
753 ObjectCapGetTransientAvail(
754 void
755 )
756 {
757 UINT32 i;
758 UINT32 num = 0;
759 //
760 // Iterate object slot to get the number of unoccupied slots
761 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
762 {
763 if(s_objects[i].attributes.occupied == FALSE) num++;
764 }
765
766 return num;
767 }
8.6.3.30 ObjectGetPublicAttributes()
768 TPMA_OBJECT
769 ObjectGetPublicAttributes(
770 TPM_HANDLE handle
771 )
772 {
773 return HandleToObject(handle)->publicArea.objectAttributes;
774 }
775 OBJECT_ATTRIBUTES
776 ObjectGetProperties(
777 TPM_HANDLE handle
778 )
779 {
780 return HandleToObject(handle)->attributes;
781 }
8.7 PCR.c
8.7.1 Introduction
This function contains the functions needed for PCR access and manipulation.
This implementation uses a static allocation for the PCR. The amount of memory is allocated based on
the number of PCR in the implementation and the number of implemented hash algorithms. This is not
the expected implementation. PCR SPACE DEFINITIONS.
In the definitions below, the g_hashPcrMap is a bit array that indicates which of the PCR are
implemented. The g_hashPcr array is an array of digests. In this implementation, the space is allocated
whether the PCR is implemented or not.
1 #define PCR_C
2 #include "Tpm.h"
The initial value of PCR attributes. The value of these fields should be consistent with PC Client
specification In this implementation, we assume the total number of implemented PCR is 24.
28 BOOL
29 PCRBelongsAuthGroup(
30 TPMI_DH_PCR handle, // IN: handle of PCR
31 UINT32 *groupIndex // OUT: group index if PCR belongs a
32 // group that allows authValue. If PCR
33 // does not belong to an authorization
8.7.2.1 PCRBelongsPolicyGroup()
This function indicates if a PCR belongs to a group that requires a policy authorization in order to modify
the PCR. If it does, groupIndex is set to value of the group index. This feature of PCR is decided by the
platform specification.
53 BOOL
54 PCRBelongsPolicyGroup(
55 TPMI_DH_PCR handle, // IN: handle of PCR
56 UINT32 *groupIndex // OUT: group index if PCR belongs a group that
57 // allows policy. If PCR does not belong to
58 // a policy group, the value in this
59 // parameter is invalid
60 )
61 {
62 #if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
63 // Platform specification decides if a PCR belongs to a policy group and
64 // belongs to which group. In this implementation, we assume there is only
65 // one policy group which contains PCR20-22. If the platform specification
66 // requires differently, the implementation should be changed accordingly
67 if(handle >= 20 && handle <= 22)
68 {
69 *groupIndex = 0;
70 return TRUE;
71 }
72 #endif
73 return FALSE;
74 }
8.7.2.2 PCRBelongsTCBGroup()
75 static BOOL
76 PCRBelongsTCBGroup(
77 TPMI_DH_PCR handle // IN: handle of PCR
78 )
79 {
80 #if ENABLE_PCR_NO_INCREMENT == YES
81 // Platform specification decides if a PCR belongs to a TCB group. In this
82 // implementation, we assume PCR[20-22] belong to TCB group. If the platform
83 // specification requires differently, the implementation should be
84 // changed accordingly
85 if(handle >= 20 && handle <= 22)
86 return TRUE;
87
88 #endif
89 return FALSE;
90 }
8.7.2.3 PCRPolicyIsAvailable()
91 BOOL
92 PCRPolicyIsAvailable(
93 TPMI_DH_PCR handle // IN: PCR handle
94 )
95 {
96 UINT32 groupIndex;
97
98 return PCRBelongsPolicyGroup(handle, &groupIndex);
99 }
8.7.2.4 PCRGetAuthValue()
This function is used to access the authValue of a PCR. If PCR does not belong to an authValue group,
an EmptyAuth() will be returned.
100 TPM2B_AUTH *
101 PCRGetAuthValue(
102 TPMI_DH_PCR handle // IN: PCR handle
103 )
104 {
105 UINT32 groupIndex;
106
107 if(PCRBelongsAuthGroup(handle, &groupIndex))
108 {
109 return &gc.pcrAuthValues.auth[groupIndex];
110 }
111 else
112 {
113 return NULL;
114 }
115 }
8.7.2.5 PCRGetAuthPolicy()
This function is used to access the authorization policy of a PCR. It sets policy to the authorization policy
and returns the hash algorithm for policy If the PCR does not allow a policy, TPM_ALG_NULL is returned.
116 TPMI_ALG_HASH
117 PCRGetAuthPolicy(
118 TPMI_DH_PCR handle, // IN: PCR handle
119 TPM2B_DIGEST *policy // OUT: policy of PCR
120 )
121 {
122 UINT32 groupIndex;
123
124 if(PCRBelongsPolicyGroup(handle, &groupIndex))
125 {
126 *policy = gp.pcrPolicies.policy[groupIndex];
127 return gp.pcrPolicies.hashAlg[groupIndex];
128 }
129 else
130 {
131 policy->t.size = 0;
132 return TPM_ALG_NULL;
133 }
134 }
8.7.2.6 PCRSimStart()
This function is used to initialize the policies when a TPM is manufactured. This function would only be
called in a manufacturing environment or in a TPM simulator.
135 void
136 PCRSimStart(
137 void
138 )
139 {
140 UINT32 i;
141 #if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
142 for(i = 0; i < NUM_POLICY_PCR_GROUP; i++)
143 {
144 gp.pcrPolicies.hashAlg[i] = TPM_ALG_NULL;
145 gp.pcrPolicies.policy[i].t.size = 0;
146 }
147 #endif
148 #if defined NUM_AUTHVALUE_PCR_GROUP && NUM_AUTHVALUE_PCR_GROUP > 0
149 for(i = 0; i < NUM_AUTHVALUE_PCR_GROUP; i++)
150 {
151 gc.pcrAuthValues.auth[i].t.size = 0;
152 }
153 #endif
154 // We need to give an initial configuration on allocated PCR before
155 // receiving any TPM2_PCR_Allocate command to change this configuration
156 // When the simulation environment starts, we allocate all the PCRs
157 for(gp.pcrAllocated.count = 0; gp.pcrAllocated.count < HASH_COUNT;
158 gp.pcrAllocated.count++)
159 {
160 gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].hash
161 = CryptHashGetAlgByIndex(gp.pcrAllocated.count);
162
163 gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].sizeofSelect
164 = PCR_SELECT_MAX;
165 for(i = 0; i < PCR_SELECT_MAX; i++)
166 gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].pcrSelect[i]
167 = 0xFF;
168 }
169
170 // Store the initial configuration to NV
171 NV_SYNC_PERSISTENT(pcrPolicies);
172 NV_SYNC_PERSISTENT(pcrAllocated);
173
174 return;
175 }
8.7.2.7 GetSavedPcrPointer()
This function returns the address of an array of state saved PCR based on the hash algorithm.
8.7.2.8 PcrIsAllocated()
This function indicates if a PCR number for the particular hash algorithm is allocated.
216 BOOL
217 PcrIsAllocated(
218 UINT32 pcr, // IN: The number of the PCR
219 TPMI_ALG_HASH hashAlg // IN: The PCR algorithm
220 )
221 {
222 UINT32 i;
223 BOOL allocated = FALSE;
224
225 if(pcr < IMPLEMENTATION_PCR)
226 {
227 for(i = 0; i < gp.pcrAllocated.count; i++)
228 {
229 if(gp.pcrAllocated.pcrSelections[i].hash == hashAlg)
230 {
231 if(((gp.pcrAllocated.pcrSelections[i].pcrSelect[pcr / 8])
232 & (1 << (pcr % 8))) != 0)
233 allocated = TRUE;
234 else
235 allocated = FALSE;
236 break;
237 }
238 }
239 }
240 return allocated;
241 }
8.7.2.9 GetPcrPointer()
This function returns the address of an array of PCR based on the hash algorithm.
259 #endif
260 #if ALG_SHA256
261 case ALG_SHA256_VALUE:
262 pcr = s_pcrs[pcrNumber].sha256Pcr;
263 break;
264 #endif
265 #if ALG_SHA384
266 case ALG_SHA384_VALUE:
267 pcr = s_pcrs[pcrNumber].sha384Pcr;
268 break;
269 #endif
270 #if ALG_SHA512
271 case ALG_SHA512_VALUE:
272 pcr = s_pcrs[pcrNumber].sha512Pcr;
273 break;
274 #endif
275 #if ALG_SM3_256
276 case ALG_SM3_256_VALUE:
277 pcr = s_pcrs[pcrNumber].sm3_256Pcr;
278 break;
279 #endif
280 default:
281 FAIL(FATAL_ERROR_INTERNAL);
282 break;
283 }
284 return pcr;
285 }
8.7.2.10 IsPcrSelected()
This function indicates if an indicated PCR number is selected by the bit map in selection.
8.7.2.11 FilterPcr()
This function modifies a PCR selection array based on the implemented PCR.
8.7.2.12 PcrDrtm()
This function does the DRTM and H-CRTM processing it is called from _TPM_Hash_End().
332 void
333 PcrDrtm(
334 const TPMI_DH_PCR pcrHandle, // IN: the index of the PCR to be
335 // modified
336 const TPMI_ALG_HASH hash, // IN: the bank identifier
337 const TPM2B_DIGEST *digest // IN: the digest to modify the PCR
338 )
339 {
340 BYTE *pcrData = GetPcrPointer(hash, pcrHandle);
341
342 if(pcrData != NULL)
343 {
344 // Rest the PCR to zeros
345 MemorySet(pcrData, 0, digest->t.size);
346
347 // if the TPM has not started, then set the PCR to 0...04 and then extend
348 if(!TPMIsStarted())
349 {
350 pcrData[digest->t.size - 1] = 4;
351 }
352 // Now, extend the value
353 PCRExtend(pcrHandle, hash, digest->t.size, (BYTE *)digest->t.buffer);
354 }
355 }
8.7.2.13 PCR_ClearAuth()
This function is used to reset the PCR authorization values. It is called on TPM2_Startup(CLEAR) and
TPM2_Clear().
356 void
357 PCR_ClearAuth(
358 void
359 )
360 {
361 #if defined NUM_AUTHVALUE_PCR_GROUP && NUM_AUTHVALUE_PCR_GROUP > 0
362 int j;
363 for(j = 0; j < NUM_AUTHVALUE_PCR_GROUP; j++)
364 {
365 gc.pcrAuthValues.auth[j].t.size = 0;
366 }
367 #endif
368 }
8.7.2.14 PCRStartup()
369 BOOL
370 PCRStartup(
371 STARTUP_TYPE type, // IN: startup type
372 BYTE locality // IN: startup locality
373 )
374 {
375 UINT32 pcr, j;
376 UINT32 saveIndex = 0;
377
378 g_pcrReConfig = FALSE;
379
380 // Don't test for SU_RESET because that should be the default when nothing
381 // else is selected
382 if(type != SU_RESUME && type != SU_RESTART)
383 {
384 // PCR generation counter is cleared at TPM_RESET
385 gr.pcrCounter = 0;
386 }
387
388 // Initialize/Restore PCR values
389 for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
390 {
391 // On resume, need to know if this PCR had its state saved or not
392 UINT32 stateSaved;
393
394 if(type == SU_RESUME
395 && s_initAttributes[pcr].stateSave == SET)
396 {
397 stateSaved = 1;
398 }
399 else
400 {
401 stateSaved = 0;
402 PCRChanged(pcr);
403 }
404
405 // If this is the H-CRTM PCR and we are not doing a resume and we
406 // had an H-CRTM event, then we don't change this PCR
407 if(pcr == HCRTM_PCR && type != SU_RESUME && g_DrtmPreStartup == TRUE)
408 continue;
409
410 // Iterate each hash algorithm bank
411 for(j = 0; j < gp.pcrAllocated.count; j++)
412 {
413 TPMI_ALG_HASH hash = gp.pcrAllocated.pcrSelections[j].hash;
414 BYTE *pcrData = GetPcrPointer(hash, pcr);
415 UINT16 pcrSize = CryptHashGetDigestSize(hash);
416
8.7.2.15 PCRStateSave()
This function is used to save the PCR values that will be restored on TPM Resume.
455 void
456 PCRStateSave(
457 TPM_SU type // IN: startup type
458 )
459 {
460 UINT32 pcr, j;
461 UINT32 saveIndex = 0;
462
463 // if state save CLEAR, nothing to be done. Return here
464 if(type == TPM_SU_CLEAR)
465 return;
466
467 // Copy PCR values to the structure that should be saved to NV
468 for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
469 {
470 UINT32 stateSaved = (s_initAttributes[pcr].stateSave == SET) ? 1 : 0;
471
472 // Iterate each hash algorithm bank
473 for(j = 0; j < gp.pcrAllocated.count; j++)
474 {
475 BYTE *pcrData;
8.7.2.16 PCRIsStateSaved()
This function indicates if the selected PCR is a PCR that is state saved on TPM2_Shutdown(STATE). The
return value is based on PCR attributes.
501 BOOL
502 PCRIsStateSaved(
503 TPMI_DH_PCR handle // IN: PCR handle to be extended
504 )
505 {
506 UINT32 pcr = handle - PCR_FIRST;
507
508 if(s_initAttributes[pcr].stateSave == SET)
509 return TRUE;
510 else
511 return FALSE;
512 }
8.7.2.17 PCRIsResetAllowed()
This function indicates if a PCR may be reset by the current command locality. The return value is based
on PCR attributes, and not the PCR allocation.
513 BOOL
514 PCRIsResetAllowed(
8.7.2.18 PCRChanged()
This function checks a PCR handle to see if the attributes for the PCR are set so that any change to the
PCR causes an increment of the pcrCounter. If it does, then the function increments the counter. Will also
bump the counter if the handle is zero which means that PCR 0 can not be in the TCB group. Bump on
zero is used by TPM2_Clear().
537 void
538 PCRChanged(
539 TPM_HANDLE pcrHandle // IN: the handle of the PCR that changed.
540 )
541 {
542 // For the reference implementation, the only change that does not cause
543 // increment is a change to a PCR in the TCB group.
544 if((pcrHandle == 0) || !PCRBelongsTCBGroup(pcrHandle))
545 {
546 gr.pcrCounter++;
547 if(gr.pcrCounter == 0)
548 FAIL(FATAL_ERROR_COUNTER_OVERFLOW);
549 }
550 }
8.7.2.19 PCRIsExtendAllowed()
This function indicates a PCR may be extended at the current command locality. The return value is
based on PCR attributes, and not the PCR allocation.
551 BOOL
552 PCRIsExtendAllowed(
553 TPMI_DH_PCR handle // IN: PCR handle to be extended
554 )
555 {
556 UINT8 commandLocality;
8.7.2.20 PCRExtend()
568 void
569 PCRExtend(
570 TPMI_DH_PCR handle, // IN: PCR handle to be extended
571 TPMI_ALG_HASH hash, // IN: hash algorithm of PCR
572 UINT32 size, // IN: size of data to be extended
573 BYTE *data // IN: data to be extended
574 )
575 {
576 BYTE *pcrData;
577 HASH_STATE hashState;
578 UINT16 pcrSize;
579
580 pcrData = GetPcrPointer(hash, handle - PCR_FIRST);
581
582 // Extend PCR if it is allocated
583 if(pcrData != NULL)
584 {
585 pcrSize = CryptHashGetDigestSize(hash);
586 CryptHashStart(&hashState, hash);
587 CryptDigestUpdate(&hashState, pcrSize, pcrData);
588 CryptDigestUpdate(&hashState, size, data);
589 CryptHashEnd(&hashState, pcrSize, pcrData);
590
591 // PCR has changed so update the pcrCounter if necessary
592 PCRChanged(handle);
593 }
594
595 return;
596 }
8.7.2.21 PCRComputeCurrentDigest()
597 void
598 PCRComputeCurrentDigest(
599 TPMI_ALG_HASH hashAlg, // IN: hash algorithm to compute digest
600 TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on
601 // output)
602 TPM2B_DIGEST *digest // OUT: digest
603 )
604 {
605 HASH_STATE hashState;
606 TPMS_PCR_SELECTION *select;
607 BYTE *pcrData; // will point to a digest
8.7.2.22 PCRRead()
This function is used to read a list of selected PCR. If the requested PCR number exceeds the maximum
number that can be output, the selection is adjusted to reflect the actual output PCR.
643 void
644 PCRRead(
645 TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on
646 // output)
647 TPML_DIGEST *digest, // OUT: digest
648 UINT32 *pcrCounter // OUT: the current value of PCR generation
649 // number
650 )
651 {
652 TPMS_PCR_SELECTION *select;
653 BYTE *pcrData; // will point to a digest
654 UINT32 pcr;
655 UINT32 i;
656
657 digest->count = 0;
658
659 // Iterate through the list of PCR selection structures
660 for(i = 0; i < selection->count; i++)
661 {
662 // Point to the current selection
663 select = &selection->pcrSelections[i]; // Point to the current selection
664 FilterPcr(select); // Clear out the bits for unimplemented PCR
665
8.7.2.23 PCRAllocate()
719 TPM_RC
720 PCRAllocate(
721 TPML_PCR_SELECTION *allocate, // IN: required allocation
722 UINT32 *maxPCR, // OUT: Maximum number of PCR
723 UINT32 *sizeNeeded, // OUT: required space
724 UINT32 *sizeAvailable // OUT: available space
725 )
726 {
727 UINT32 i, j, k;
728 TPML_PCR_SELECTION newAllocate;
729 // Initialize the flags to indicate if HCRTM PCR and DRTM PCR are allocated.
730 BOOL pcrHcrtm = FALSE;
731 BOOL pcrDrtm = FALSE;
732
733 // Create the expected new PCR allocation based on the existing allocation
734 // and the new input:
735 // 1. if a PCR bank does not appear in the new allocation, the existing
736 // allocation of this PCR bank will be preserved.
737 // 2. if a PCR bank appears multiple times in the new allocation, only the
738 // last one will be in effect.
739 newAllocate = gp.pcrAllocated;
740 for(i = 0; i < allocate->count; i++)
741 {
742 for(j = 0; j < newAllocate.count; j++)
743 {
744 // If hash matches, the new allocation covers the old allocation
745 // for this particular bank.
746 // The assumption is the initial PCR allocation (from manufacture)
747 // has all the supported hash algorithms with an assigned bank
748 // (possibly empty). So there must be a match for any new bank
749 // allocation from the input.
750 if(newAllocate.pcrSelections[j].hash ==
751 allocate->pcrSelections[i].hash)
752 {
753 newAllocate.pcrSelections[j] = allocate->pcrSelections[i];
754 break;
755 }
756 }
757 // The j loop must exit with a match.
758 pAssert(j < newAllocate.count);
759 }
760
761 // Max PCR in a bank is MIN(implemented PCR, PCR with attributes defined)
762 *maxPCR = sizeof(s_initAttributes) / sizeof(PCR_Attributes);
763 if(*maxPCR > IMPLEMENTATION_PCR)
764 *maxPCR = IMPLEMENTATION_PCR;
765
766 // Compute required size for allocation
767 *sizeNeeded = 0;
768 for(i = 0; i < newAllocate.count; i++)
769 {
770 UINT32 digestSize
771 = CryptHashGetDigestSize(newAllocate.pcrSelections[i].hash);
772 #if defined(DRTM_PCR)
773 // Make sure that we end up with at least one DRTM PCR
774 pcrDrtm = pcrDrtm || TestBit(DRTM_PCR,
775 newAllocate.pcrSelections[i].pcrSelect,
776 newAllocate.pcrSelections[i].sizeofSelect);
777
778 #else // if DRTM PCR is not required, indicate that the allocation is OK
779 pcrDrtm = TRUE;
780 #endif
781
782 #if defined(HCRTM_PCR)
783 // and one HCRTM PCR (since this is usually PCR 0...)
784 pcrHcrtm = pcrHcrtm || TestBit(HCRTM_PCR,
785 newAllocate.pcrSelections[i].pcrSelect,
786 newAllocate.pcrSelections[i].sizeofSelect);
787 #else
788 pcrHcrtm = TRUE;
789 #endif
790 for(j = 0; j < newAllocate.pcrSelections[i].sizeofSelect; j++)
791 {
792 BYTE mask = 1;
793 for(k = 0; k < 8; k++)
794 {
795 if((newAllocate.pcrSelections[i].pcrSelect[j] & mask) != 0)
796 *sizeNeeded += digestSize;
797 mask = mask << 1;
798 }
799 }
800 }
801
802 if(!pcrDrtm || !pcrHcrtm)
803 return TPM_RC_PCR;
804
805 // In this particular implementation, we always have enough space to
806 // allocate PCR. Different implementation may return a sizeAvailable less
807 // than the sizeNeed.
808 *sizeAvailable = sizeof(s_pcrs);
809
810 // Save the required allocation to NV. Note that after NV is written, the
811 // PCR allocation in NV is no longer consistent with the RAM data
812 // gp.pcrAllocated. The NV version reflect the allocate after next
813 // TPM_RESET, while the RAM version reflects the current allocation
814 NV_WRITE_PERSISTENT(pcrAllocated, newAllocate);
815
816 return TPM_RC_SUCCESS;
817 }
8.7.2.24 PCRSetValue()
This function is used to set the designated PCR in all banks to an initial value. The initial value is signed
and will be sign extended into the entire PCR.
818 void
819 PCRSetValue(
820 TPM_HANDLE handle, // IN: the handle of the PCR to set
821 INT8 initialValue // IN: the value to set
822 )
823 {
824 int i;
825 UINT32 pcr = handle - PCR_FIRST;
826 TPMI_ALG_HASH hash;
827 UINT16 digestSize;
828 BYTE *pcrData;
829
830 // Iterate supported PCR bank algorithms to reset
831 for(i = 0; i < HASH_COUNT; i++)
832 {
833 hash = CryptHashGetAlgByIndex(i);
834 // Prevent runaway
835 if(hash == TPM_ALG_NULL)
836 break;
837
838 // Get a pointer to the data
839 pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
840
841 // If the PCR is allocated
842 if(pcrData != NULL)
843 {
844 // And the size of the digest
845 digestSize = CryptHashGetDigestSize(hash);
846
847 // Set the LSO to the input value
848 pcrData[digestSize - 1] = initialValue;
849
850 // Sign extend
851 if(initialValue >= 0)
852 MemorySet(pcrData, 0, digestSize - 1);
853 else
854 MemorySet(pcrData, -1, digestSize - 1);
855 }
856 }
857 }
8.7.2.25 PCRResetDynamics
This function is used to reset a dynamic PCR to 0. This function is used in DRTM sequence.
858 void
859 PCRResetDynamics(
860 void
861 )
862 {
863 UINT32 pcr, i;
864
865 // Initialize PCR values
866 for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
867 {
868 // Iterate each hash algorithm bank
869 for(i = 0; i < gp.pcrAllocated.count; i++)
870 {
871 BYTE *pcrData;
872 UINT32 pcrSize;
873
874 pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr);
875
876 if(pcrData != NULL)
877 {
878 pcrSize =
879 CryptHashGetDigestSize(gp.pcrAllocated.pcrSelections[i].hash);
880
881 // Reset PCR
882 // Any PCR can be reset by locality 4 should be reset to 0
883 if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
884 MemorySet(pcrData, 0, pcrSize);
885 }
886 }
887 }
888 return;
889 }
8.7.2.26 PCRCapGetAllocation()
890 TPMI_YES_NO
891 PCRCapGetAllocation(
892 UINT32 count, // IN: count of return
893 TPML_PCR_SELECTION *pcrSelection // OUT: PCR allocation list
894 )
895 {
896 if(count == 0)
897 {
898 pcrSelection->count = 0;
899 return YES;
900 }
901 else
902 {
903 *pcrSelection = gp.pcrAllocated;
904 return NO;
905 }
906 }
8.7.2.27 PCRSetSelectBit()
8.7.2.28 PCRGetProperty()
996 break;
997 #endif
998 #if ENABLE_PCR_NO_INCREMENT == YES
999 case TPM_PT_PCR_NO_INCREMENT:
1000 if(PCRBelongsTCBGroup(pcr + PCR_FIRST))
1001 PCRSetSelectBit(pcr, select->pcrSelect);
1002 break;
1003 #endif
1004 default:
1005 // If property is not supported, stop scanning PCR attributes
1006 // and return.
1007 return FALSE;
1008 break;
1009 }
1010 }
1011 return TRUE;
1012 }
8.7.2.29 PCRCapGetProperties()
1013 TPMI_YES_NO
1014 PCRCapGetProperties(
1015 TPM_PT_PCR property, // IN: the starting PCR property
1016 UINT32 count, // IN: count of returned properties
1017 TPML_TAGGED_PCR_PROPERTY *select // OUT: PCR select
1018 )
1019 {
1020 TPMI_YES_NO more = NO;
1021 UINT32 i;
1022
1023 // Initialize output property list
1024 select->count = 0;
1025
1026 // The maximum count of properties we may return is MAX_PCR_PROPERTIES
1027 if(count > MAX_PCR_PROPERTIES) count = MAX_PCR_PROPERTIES;
1028
1029 // TPM_PT_PCR_FIRST is defined as 0 in spec. It ensures that property
1030 // value would never be less than TPM_PT_PCR_FIRST
1031 cAssert(TPM_PT_PCR_FIRST == 0);
1032
1033 // Iterate PCR properties. TPM_PT_PCR_LAST is the index of the last property
1034 // implemented on the TPM.
1035 for(i = property; i <= TPM_PT_PCR_LAST; i++)
1036 {
1037 if(select->count < count)
1038 {
1039 // If we have not filled up the return list, add more properties to it
1040 if(PCRGetProperty(i, &select->pcrProperty[select->count]))
1041 // only increment if the property is implemented
1042 select->count++;
1043 }
1044 else
1045 {
1046 // If the return list is full but we still have properties
1047 // available, report this and stop iterating.
1048 more = YES;
1049 break;
1050 }
1051 }
1052 return more;
1053 }
8.7.2.30 PCRCapGetHandles()
This function is used to get a list of handles of PCR, started from handle. If handle exceeds the maximum
PCR handle range, an empty list will be returned and the return value will be NO.
1054 TPMI_YES_NO
1055 PCRCapGetHandles(
1056 TPMI_DH_PCR handle, // IN: start handle
1057 UINT32 count, // IN: count of returned handles
1058 TPML_HANDLE *handleList // OUT: list of handle
1059 )
1060 {
1061 TPMI_YES_NO more = NO;
1062 UINT32 i;
1063
1064 pAssert(HandleGetType(handle) == TPM_HT_PCR);
1065
1066 // Initialize output handle list
1067 handleList->count = 0;
1068
1069 // The maximum count of handles we may return is MAX_CAP_HANDLES
1070 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1071
1072 // Iterate PCR handle range
1073 for(i = handle & HR_HANDLE_MASK; i <= PCR_LAST; i++)
1074 {
1075 if(handleList->count < count)
1076 {
1077 // If we have not filled up the return list, add this PCR
1078 // handle to it
1079 handleList->handle[handleList->count] = i + PCR_FIRST;
1080 handleList->count++;
1081 }
1082 else
1083 {
1084 // If the return list is full but we still have PCR handle
1085 // available, report this and stop iterating
1086 more = YES;
1087 break;
1088 }
1089 }
1090 return more;
1091 }
8.8 PP.c
8.8.1 Introduction
This file contains the functions that support the physical presence operations of the TPM.
8.8.2 Includes
1 #include "Tpm.h"
8.8.3 Functions
8.8.3.1 PhysicalPresencePreInstall_Init()
This function is used to initialize the array of commands that always require confirmation with physical
presence. The array is an array of bits that has a correspondence with the command code.
This command should only ever be executable in a manufacturing setting or in a simulation.
When set, these cannot be cleared.
2 void
3 PhysicalPresencePreInstall_Init(
4 void
5 )
6 {
7 COMMAND_INDEX commandIndex;
8 // Clear all the PP commands
9 MemorySet(&gp.ppList, 0, sizeof(gp.ppList));
10
11 // Any command that is PP_REQUIRED should be SET
12 for(commandIndex = 0; commandIndex < COMMAND_COUNT; commandIndex++)
13 {
14 if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED
15 && s_commandAttributes[commandIndex] & PP_REQUIRED)
16 SET_BIT(commandIndex, gp.ppList);
17 }
18 // Write PP list to NV
19 NV_SYNC_PERSISTENT(ppList);
20 return;
21 }
8.8.3.2 PhysicalPresenceCommandSet()
This function is used to set the indicator that a command requires PP confirmation.
22 void
23 PhysicalPresenceCommandSet(
24 TPM_CC commandCode // IN: command code
25 )
26 {
27 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
28
29 // if the command isn't implemented, the do nothing
30 if(commandIndex == UNIMPLEMENTED_COMMAND_INDEX)
31 return;
32
33 // only set the bit if this is a command for which PP is allowed
34 if(s_commandAttributes[commandIndex] & PP_COMMAND)
35 SET_BIT(commandIndex, gp.ppList);
36 return;
37 }
8.8.3.3 PhysicalPresenceCommandClear()
This function is used to clear the indicator that a command requires PP confirmation.
38 void
39 PhysicalPresenceCommandClear(
40 TPM_CC commandCode // IN: command code
41 )
42 {
43 COMMAND_INDEX commandIndex = CommandCodeToCommandIndex(commandCode);
44
45 // If the command isn't implemented, then don't do anything
46 if(commandIndex == UNIMPLEMENTED_COMMAND_INDEX)
47 return;
48
49 // Only clear the bit if the command does not require PP
50 if((s_commandAttributes[commandIndex] & PP_REQUIRED) == 0)
51 CLEAR_BIT(commandIndex, gp.ppList);
52
53 return;
54 }
8.8.3.4 PhysicalPresenceIsRequired()
55 BOOL
56 PhysicalPresenceIsRequired(
57 COMMAND_INDEX commandIndex // IN: command index
58 )
59 {
60 // Check the bit map. If the bit is SET, PP authorization is required
61 return (TEST_BIT(commandIndex, gp.ppList));
62 }
8.8.3.5 PhysicalPresenceCapGetCCList()
This function returns a list of commands that require PP confirmation. The list starts from the first
implemented command that has a command code that the same or greater than commandCode.
63 TPMI_YES_NO
64 PhysicalPresenceCapGetCCList(
65 TPM_CC commandCode, // IN: start command code
66 UINT32 count, // IN: count of returned TPM_CC
67 TPML_CC *commandList // OUT: list of TPM_CC
68 )
69 {
70 TPMI_YES_NO more = NO;
71 COMMAND_INDEX commandIndex;
72
73 // Initialize output handle list
74 commandList->count = 0;
75
76 // The maximum count of command we may return is MAX_CAP_CC
77 if(count > MAX_CAP_CC) count = MAX_CAP_CC;
78
79 // Collect PP commands
80 for(commandIndex = GetClosestCommandIndex(commandCode);
81 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
82 commandIndex = GetNextCommandIndex(commandIndex))
83 {
84 if(PhysicalPresenceIsRequired(commandIndex))
85 {
86 if(commandList->count < count)
87 {
88 // If we have not filled up the return list, add this command
89 // code to it
90 commandList->commandCodes[commandList->count]
91 = GetCommandCode(commandIndex);
92 commandList->count++;
93 }
94 else
95 {
96 // If the return list is full but we still have PP command
97 // available, report this and stop iterating
98 more = YES;
99 break;
100 }
101 }
102 }
103 return more;
104 }
8.9 Session.c
8.9.1 Introduction
The code in this file is used to manage the session context counter. The scheme implemented here is a
"truncated counter". This scheme allows the TPM to not need TPM_SU_CLEAR for a very long period of
time and still not have the context count for a session repeated.
The counter (contextCounter)in this implementation is a UINT64 but can be smaller. The "tracking array"
(contextArray) only has 16-bits per context. The tracking array is the data that needs to be saved and
restored across TPM_SU_STATE so that sessions are not lost when the system enters the sleep state.
Also, when the TPM is active, the tracking array is kept in RAM making it important that the number of
bytes for each entry be kept as small as possible.
The TPM prevents collisions of these truncated values by not allowing a contextID to be assigned if it
would be the same as an existing value. Since the array holds 16 bits, after a context has been saved, an
additional 2^16-1 contexts may be saved before the count would again match. The normal expectation is
that the context will be flushed before its count value is needed again but it is always possible to have
long-lived sessions.
The contextID is assigned when the context is saved (TPM2_ContextSave()). At that time, the TPM will
compare the low-order 16 bits of contextCounter to the existing values in contextArray and if one
matches, the TPM will return TPM_RC_CONTEXT_GAP (by construction, the entry that contains the
matching value is the oldest context).
The expected remediation by the TRM is to load the oldest saved session context (the one found by the
TPM), and save it. Since loading the oldest session also eliminates its contextID value from contextArray,
there TPM will always be able to load and save the oldest existing context.
In the worst case, software may have to load and save several contexts in order to save an additional
one. This should happen very infrequently.
When the TPM searches contextArray and finds that none of the contextIDs match the low-order 16-bits
of contextCount, the TPM can copy the low bits to the contextArray associated with the session, and
increment contextCount.
There is one entry in contextArray for each of the active sessions allowed by the TPM implementation.
This array contains either a context count, an index, or a value indicating the slot is available (0).
The index into the contextArray is the handle for the session with the region selector byte of the session
set to zero. If an entry in contextArray contains 0, then the corresponding handle may be assigned to a
session. If the entry contains a value that is less than or equal to the number of loaded sessions for the
TPM, then the array entry is the slot in which the context is loaded.
EXAMPLE: If the TPM allows 8 loaded sessions, then the slot numbers would be 1-8 and a contextArrary value in that
range would represent the loaded session.
NOTE: When the TPM firmware determines that the array entry is for a loaded session, it will subtract 1 to create the
zero-based slot number.
There is one significant corner case in this scheme. When the contextCount is equal to a value in the
contextArray, the oldest session needs to be recycled or flushed. In order to recycle the session, it must
be loaded. To be loaded, there must be an available slot. Rather than require that a spare slot be
available all the time, the TPM will check to see if the contextCount is equal to some value in the
contextArray when a session is created. This prevents the last session slot from being used when it is
likely that a session will need to be recycled.
If a TPM with both 1.2 and 2.0 functionality uses this scheme for both 1.2 and 2.0 sessions, and the list of
active contexts is read with TPM_GetCapabiltiy(), the TPM will create 32-bit representations of the list that
contains 16-bit values (the TPM2_GetCapability() returns a list of handles for active sessions rather than
a list of contextID). The full contextID has high-order bits that are either the same as the current
contextCount or one less. It is one less if the 16-bits of the contextArray has a value that is larger than the
low-order 16 bits of contextCount.
1 #define SESSION_C
2 #include "Tpm.h"
This function is called when the oldest contextID is being loaded or deleted. Once a saved context
becomes the oldest, it stays the oldest until it is deleted.
Finding the oldest is a bit tricky. It is not just the numeric comparison of values but is dependent on the
value of contextCounter.
Assume we have a small contextArray with 8, 4-bit values with values 1 and 2 used to indicate the loaded
context slot number. Also assume that the array contains hex values of (0 0 1 0 3 0 9 F) and that the
contextCounter is an 8-bit counter with a value of 0x37. Since the low nibble is 7, that means that values
closest to but above 7 are older than values below it and, in this example, 9 is the oldest value.
Note if we subtract the counter value, from each slot that contains a saved contextID we get (- - - - B - 2 -
8) and the oldest entry is now easy to find because it has the lowest value.
3 static void
4 ContextIdSetOldest(
5 void
6 )
7 {
8 CONTEXT_SLOT lowBits;
9 CONTEXT_SLOT entry;
10 CONTEXT_SLOT smallest = ((CONTEXT_SLOT)~0); // Set to the maximum possible
11 UINT32 i;
12
13 // Set oldestSaveContext to a value indicating none assigned
14 s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
15
16 lowBits = (CONTEXT_SLOT)gr.contextCounter;
17 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
18 {
19 entry = gr.contextArray[i];
20
21 // only look at entries that are saved contexts
22 if(entry > MAX_LOADED_SESSIONS)
23 {
24 // Use a less than or equal in case the oldest
25 // is brand new (= lowBits-1) and equal to our initial
26 // value for smallest.
27 if(((CONTEXT_SLOT)(entry - lowBits)) <= smallest)
28 {
29 smallest = (entry - lowBits);
30 s_oldestSavedSession = i;
31 }
32 }
33 }
34 // When we finish, either the s_oldestSavedSession still has its initial
35 // value, or it has the index of the oldest saved context.
36 }
37 BOOL
38 SessionStartup(
39 STARTUP_TYPE type
40 )
41 {
42 UINT32 i;
43
44 // Initialize session slots. At startup, all the in-memory session slots
45 // are cleared and marked as not occupied
46 for(i = 0; i < MAX_LOADED_SESSIONS; i++)
47 s_sessions[i].occupied = FALSE; // session slot is not occupied
48
49 // The free session slots the number of maximum allowed loaded sessions
50 s_freeSessionSlots = MAX_LOADED_SESSIONS;
51
52 // Initialize context ID data. On a ST_SAVE or hibernate sequence, it will
53 // scan the saved array of session context counts, and clear any entry that
54 // references a session that was in memory during the state save since that
55 // memory was not preserved over the ST_SAVE.
56 if(type == SU_RESUME || type == SU_RESTART)
57 {
58 // On ST_SAVE we preserve the contexts that were saved but not the ones
59 // in memory
60 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
61 {
62 // If the array value is unused or references a loaded session then
63 // that loaded session context is lost and the array entry is
64 // reclaimed.
65 if(gr.contextArray[i] <= MAX_LOADED_SESSIONS)
66 gr.contextArray[i] = 0;
67 }
68 // Find the oldest session in context ID data and set it in
69 // s_oldestSavedSession
70 ContextIdSetOldest();
71 }
72 else
73 {
74 // For STARTUP_CLEAR, clear out the contextArray
75 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
76 gr.contextArray[i] = 0;
77
78 // reset the context counter
79 gr.contextCounter = MAX_LOADED_SESSIONS + 1;
80
81 // Initialize oldest saved session
82 s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1;
83 }
84 return TRUE;
85 }
8.9.5.1 SessionIsLoaded()
This function test a session handle references a loaded session. The handle must have previously been
checked to make sure that it is a valid handle for an authorization session.
86 BOOL
87 SessionIsLoaded(
88 TPM_HANDLE handle // IN: session handle
89 )
90 {
91 pAssert(HandleGetType(handle) == TPM_HT_POLICY_SESSION
92 || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
93
94 handle = handle & HR_HANDLE_MASK;
95
96 // if out of range of possible active session, or not assigned to a loaded
97 // session return false
98 if(handle >= MAX_ACTIVE_SESSIONS
99 || gr.contextArray[handle] == 0
100 || gr.contextArray[handle] > MAX_LOADED_SESSIONS)
101 return FALSE;
102
103 return TRUE;
104 }
8.9.5.2 SessionIsSaved()
This function test a session handle references a saved session. The handle must have previously been
checked to make sure that it is a valid handle for an authorization session.
105 BOOL
106 SessionIsSaved(
107 TPM_HANDLE handle // IN: session handle
108 )
109 {
110 pAssert(HandleGetType(handle) == TPM_HT_POLICY_SESSION
111 || HandleGetType(handle) == TPM_HT_HMAC_SESSION);
112
113 handle = handle & HR_HANDLE_MASK;
114 // if out of range of possible active session, or not assigned, or
115 // assigned to a loaded session, return false
116 if(handle >= MAX_ACTIVE_SESSIONS
117 || gr.contextArray[handle] == 0
118 || gr.contextArray[handle] <= MAX_LOADED_SESSIONS
119 )
120 return FALSE;
121
122 return TRUE;
123 }
8.9.5.3 SequenceNumberForSavedContextIsValid()
This function validates that the sequence number and handle value within a saved context are valid.
124 BOOL
125 SequenceNumberForSavedContextIsValid(
126 TPMS_CONTEXT *context // IN: pointer to a context structure to be
127 // validated
128 )
129 {
130 #define MAX_CONTEXT_GAP ((UINT64)((CONTEXT_SLOT) ~0) + 1)
131
132 TPM_HANDLE handle = context->savedHandle & HR_HANDLE_MASK;
133
134 if(// Handle must be with the range of active sessions
135 handle >= MAX_ACTIVE_SESSIONS
136 // the array entry must be for a saved context
137 || gr.contextArray[handle] <= MAX_LOADED_SESSIONS
138 // the array entry must agree with the sequence number
139 || gr.contextArray[handle] != (CONTEXT_SLOT)context->sequence
140 // the provided sequence number has to be less than the current counter
141 || context->sequence > gr.contextCounter
142 // but not so much that it could not be a valid sequence number
143 || gr.contextCounter - context->sequence > MAX_CONTEXT_GAP)
144 return FALSE;
145
146 return TRUE;
147 }
8.9.5.4 SessionPCRValueIsCurrent()
This function is used to check if PCR values have been updated since the last time they were checked in
a policy session.
This function requires the session is loaded.
148 BOOL
149 SessionPCRValueIsCurrent(
150 SESSION *session // IN: session structure
151 )
152 {
153 if(session->pcrCounter != 0
154 && session->pcrCounter != gr.pcrCounter
155 )
156 return FALSE;
157 else
158 return TRUE;
159 }
8.9.5.5 SessionGet()
This function returns a pointer to the session object associated with a session handle.
The function requires that the session is loaded.
160 SESSION *
161 SessionGet(
162 TPM_HANDLE handle // IN: session handle
163 )
164 {
165 size_t slotIndex;
166 CONTEXT_SLOT sessionIndex;
167
168 pAssert(HandleGetType(handle) == TPM_HT_POLICY_SESSION
169 || HandleGetType(handle) == TPM_HT_HMAC_SESSION
170 );
171
172 slotIndex = handle & HR_HANDLE_MASK;
173
174 pAssert(slotIndex < MAX_ACTIVE_SESSIONS);
175
176 // get the contents of the session array. Because session is loaded, we
177 // should always get a valid sessionIndex
178 sessionIndex = gr.contextArray[slotIndex] - 1;
179
180 pAssert(sessionIndex < MAX_LOADED_SESSIONS);
181
182 return &s_sessions[sessionIndex].session;
183 }
8.9.6.1 ContextIdSessionCreate()
This function is called when a session is created. It will check to see if the current gap would prevent a
context from being saved. If so it will return TPM_RC_CONTEXT_GAP. Otherwise, it will try to find an
open slot in contextArray, set contextArray to the slot.
This routine requires that the caller has determined the session array index for the session.
205 // The current value of the contextCounter will be assigned to the next
206 // saved context. If the value to be assigned would make the same as an
207 // existing context, then we can't use it because of the ambiguity it would
208 // create.
209 if((CONTEXT_SLOT)gr.contextCounter
210 == gr.contextArray[s_oldestSavedSession])
211 return TPM_RC_CONTEXT_GAP;
212 }
213
214 // Find an unoccupied entry in the contextArray
215 for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++)
216 {
217 if(gr.contextArray[*handle] == 0)
218 {
219 // indicate that the session associated with this handle
220 // references a loaded session
221 gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex + 1);
222 return TPM_RC_SUCCESS;
223 }
224 }
225 return TPM_RC_SESSION_HANDLES;
226 }
8.9.6.2 SessionCreate()
This function does the detailed work for starting an authorization session. This is done in a support
routine rather than in the action code because the session management may differ in implementations.
This implementation uses a fixed memory allocation to hold sessions and a fixed allocation to hold the
contextID for the saved contexts.
227 TPM_RC
228 SessionCreate(
229 TPM_SE sessionType, // IN: the session type
230 TPMI_ALG_HASH authHash, // IN: the hash algorithm
231 TPM2B_NONCE *nonceCaller, // IN: initial nonceCaller
232 TPMT_SYM_DEF *symmetric, // IN: the symmetric algorithm
233 TPMI_DH_ENTITY bind, // IN: the bind object
234 TPM2B_DATA *seed, // IN: seed data
235 TPM_HANDLE *sessionHandle, // OUT: the session handle
236 TPM2B_NONCE *nonceTpm // OUT: the session nonce
237 )
238 {
239 TPM_RC result = TPM_RC_SUCCESS;
240 CONTEXT_SLOT slotIndex;
241 SESSION *session = NULL;
242
243 pAssert(sessionType == TPM_SE_HMAC
244 || sessionType == TPM_SE_POLICY
245 || sessionType == TPM_SE_TRIAL);
246
247 // If there are no open spots in the session array, then no point in searching
248 if(s_freeSessionSlots == 0)
249 return TPM_RC_SESSION_MEMORY;
250
251 // Find a space for loading a session
252 for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
253 {
254 // Is this available?
255 if(s_sessions[slotIndex].occupied == FALSE)
256 {
257 session = &s_sessions[slotIndex].session;
258 break;
259 }
260 }
261 // if no spot found, then this is an internal error
262 if(slotIndex >= MAX_LOADED_SESSIONS)
263 FAIL(FATAL_ERROR_INTERNAL);
264
265 // Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be
266 // returned from ContextIdHandelAssign()
267 result = ContextIdSessionCreate(sessionHandle, slotIndex);
268 if(result != TPM_RC_SUCCESS)
269 return result;
270
271 //*** Only return from this point on is TPM_RC_SUCCESS
272
273 // Can now indicate that the session array entry is occupied.
274 s_freeSessionSlots--;
275 s_sessions[slotIndex].occupied = TRUE;
276
277 // Initialize the session data
278 MemorySet(session, 0, sizeof(SESSION));
279
280 // Initialize internal session data
281 session->authHashAlg = authHash;
282 // Initialize session type
283 if(sessionType == TPM_SE_HMAC)
284 {
285 *sessionHandle += HMAC_SESSION_FIRST;
286 }
287 else
288 {
289 *sessionHandle += POLICY_SESSION_FIRST;
290
291 // For TPM_SE_POLICY or TPM_SE_TRIAL
292 session->attributes.isPolicy = SET;
293 if(sessionType == TPM_SE_TRIAL)
294 session->attributes.isTrialPolicy = SET;
295
296 SessionSetStartTime(session);
297
298 // Initialize policyDigest. policyDigest is initialized with a string of 0
299 // of session algorithm digest size. Since the session is already clear.
300 // Just need to set the size
301 session->u2.policyDigest.t.size =
302 CryptHashGetDigestSize(session->authHashAlg);
303 }
304 // Create initial session nonce
305 session->nonceTPM.t.size = nonceCaller->t.size;
306 CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
307 MemoryCopy2B(&nonceTpm->b, &session->nonceTPM.b,
308 sizeof(nonceTpm->t.buffer));
309
310 // Set up session parameter encryption algorithm
311 session->symmetric = *symmetric;
312
313 // If there is a bind object or a session secret, then need to compute
314 // a sessionKey.
315 if(bind != TPM_RH_NULL || seed->t.size != 0)
316 {
317 // sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM,
318 // nonceCaller, bits)
319 // The HMAC key for generating the sessionSecret can be the concatenation
320 // of an authorization value and a seed value
321 TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer)));
322 TPM2B_KEY key;
323
324 // Get hash size, which is also the length of sessionKey
325 session->sessionKey.t.size = CryptHashGetDigestSize(session->authHashAlg);
326
327 // Get authValue of associated entity
328 EntityGetAuthValue(bind, (TPM2B_AUTH *)&key);
329 pAssert(key.t.size + seed->t.size <= sizeof(key.t.buffer));
330
331 // Concatenate authValue and seed
332 MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer));
333
334 // Compute the session key
335 CryptKDFa(session->authHashAlg, &key.b, SESSION_KEY, &session->nonceTPM.b,
336 &nonceCaller->b,
337 session->sessionKey.t.size * 8, session->sessionKey.t.buffer,
338 NULL, FALSE);
339 }
340
341 // Copy the name of the entity that the HMAC session is bound to
342 // Policy session is not bound to an entity
343 if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC)
344 {
345 session->attributes.isBound = SET;
346 SessionComputeBoundEntity(bind, &session->u1.boundEntity);
347 }
348 // If there is a bind object and it is subject to DA, then use of this session
349 // is subject to DA regardless of how it is used.
350 session->attributes.isDaBound = (bind != TPM_RH_NULL)
351 && (IsDAExempted(bind) == FALSE);
352
353 // If the session is bound, then check to see if it is bound to lockoutAuth
354 session->attributes.isLockoutBound = (session->attributes.isDaBound == SET)
355 && (bind == TPM_RH_LOCKOUT);
356 return TPM_RC_SUCCESS;
357 }
8.9.6.3 SessionContextSave()
This function is called when a session context is to be saved. The contextID of the saved session is
returned. If no contextID can be assigned, then the routine returns TPM_RC_CONTEXT_GAP. If the
function completes normally, the session slot will be freed.
This function requires that handle references a loaded session. Otherwise, it should not be called at the
first place.
358 TPM_RC
359 SessionContextSave(
360 TPM_HANDLE handle, // IN: session handle
361 CONTEXT_COUNTER *contextID // OUT: assigned contextID
362 )
363 {
364 UINT32 contextIndex;
365 CONTEXT_SLOT slotIndex;
366
367 pAssert(SessionIsLoaded(handle));
368
369 // check to see if the gap is already maxed out
370 // Need to have a saved session
371 if(s_oldestSavedSession < MAX_ACTIVE_SESSIONS
372 // if the oldest saved session has the same value as the low bits
373 // of the contextCounter, then the GAP is maxed out.
374 && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter)
375 return TPM_RC_CONTEXT_GAP;
376
377 // if the caller wants the context counter, set it
378 if(contextID != NULL)
379 *contextID = gr.contextCounter;
380
381 contextIndex = handle & HR_HANDLE_MASK;
382 pAssert(contextIndex < MAX_ACTIVE_SESSIONS);
383
384 // Extract the session slot number referenced by the contextArray
385 // because we are going to overwrite this with the low order
386 // contextID value.
387 slotIndex = gr.contextArray[contextIndex] - 1;
388
389 // Set the contextID for the contextArray
390 gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter;
391
392 // Increment the counter
393 gr.contextCounter++;
394
395 // In the unlikely event that the 64-bit context counter rolls over...
396 if(gr.contextCounter == 0)
397 {
398 // back it up
399 gr.contextCounter--;
400 // return an error
401 return TPM_RC_TOO_MANY_CONTEXTS;
402 }
403 // if the low-order bits wrapped, need to advance the value to skip over
404 // the values used to indicate that a session is loaded
405 if(((CONTEXT_SLOT)gr.contextCounter) == 0)
406 gr.contextCounter += MAX_LOADED_SESSIONS + 1;
407
408 // If no other sessions are saved, this is now the oldest.
409 if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS)
410 s_oldestSavedSession = contextIndex;
411
412 // Mark the session slot as unoccupied
413 s_sessions[slotIndex].occupied = FALSE;
414
415 // and indicate that there is an additional open slot
416 s_freeSessionSlots++;
417
418 return TPM_RC_SUCCESS;
419 }
8.9.6.4 SessionContextLoad()
This function is used to load a session from saved context. The session handle must be for a saved
context.
If the gap is at a maximum, then the only session that can be loaded is the oldest session, otherwise
TPM_RC_CONTEXT_GAP is returned.
This function requires that handle references a valid saved session.
420 TPM_RC
421 SessionContextLoad(
422 SESSION_BUF *session, // IN: session structure from saved context
423 TPM_HANDLE *handle // IN/OUT: session handle
424 )
425 {
426 UINT32 contextIndex;
427 CONTEXT_SLOT slotIndex;
428
429 pAssert(HandleGetType(*handle) == TPM_HT_POLICY_SESSION
430 || HandleGetType(*handle) == TPM_HT_HMAC_SESSION);
431
432 // Don't bother looking if no openings
433 if(s_freeSessionSlots == 0)
434 return TPM_RC_SESSION_MEMORY;
435
436 // Find a free session slot to load the session
437 for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
438 if(s_sessions[slotIndex].occupied == FALSE) break;
439
440 // if no spot found, then this is an internal error
441 pAssert(slotIndex < MAX_LOADED_SESSIONS);
442
443 contextIndex = *handle & HR_HANDLE_MASK; // extract the index
444
445 // If there is only one slot left, and the gap is at maximum, the only session
446 // context that we can safely load is the oldest one.
447 if(s_oldestSavedSession < MAX_ACTIVE_SESSIONS
448 && s_freeSessionSlots == 1
449 && (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession]
450 && contextIndex != s_oldestSavedSession)
451 return TPM_RC_CONTEXT_GAP;
452
453 pAssert(contextIndex < MAX_ACTIVE_SESSIONS);
454
455 // set the contextArray value to point to the session slot where
456 // the context is loaded
457 gr.contextArray[contextIndex] = slotIndex + 1;
458
459 // if this was the oldest context, find the new oldest
460 if(contextIndex == s_oldestSavedSession)
461 ContextIdSetOldest();
462
463 // Copy session data to session slot
464 MemoryCopy(&s_sessions[slotIndex].session, session, sizeof(SESSION));
465
466 // Set session slot as occupied
467 s_sessions[slotIndex].occupied = TRUE;
468
469 // Reduce the number of open spots
470 s_freeSessionSlots--;
471
472 return TPM_RC_SUCCESS;
473 }
8.9.6.5 SessionFlush()
This function is used to flush a session referenced by its handle. If the session associated with handle is
loaded, the session array entry is marked as available.
This function requires that handle be a valid active session.
474 void
475 SessionFlush(
476 TPM_HANDLE handle // IN: loaded or saved session handle
477 )
478 {
479 CONTEXT_SLOT slotIndex;
480 UINT32 contextIndex; // Index into contextArray
481
482 pAssert((HandleGetType(handle) == TPM_HT_POLICY_SESSION
483 || HandleGetType(handle) == TPM_HT_HMAC_SESSION
484 )
485 && (SessionIsLoaded(handle) || SessionIsSaved(handle))
486 );
487
488 // Flush context ID of this session
489 // Convert handle to an index into the contextArray
490 contextIndex = handle & HR_HANDLE_MASK;
491
492 pAssert(contextIndex < sizeof(gr.contextArray) / sizeof(gr.contextArray[0]));
493
494 // Get the current contents of the array
495 slotIndex = gr.contextArray[contextIndex];
496
497 // Mark context array entry as available
498 gr.contextArray[contextIndex] = 0;
499
500 // Is this a saved session being flushed
501 if(slotIndex > MAX_LOADED_SESSIONS)
502 {
503 // Flushing the oldest session?
504 if(contextIndex == s_oldestSavedSession)
505 // If so, find a new value for oldest.
506 ContextIdSetOldest();
507 }
508 else
509 {
510 // Adjust slot index to point to session array index
511 slotIndex -= 1;
512
513 // Free session array index
514 s_sessions[slotIndex].occupied = FALSE;
515 s_freeSessionSlots++;
516 }
517
518 return;
519 }
8.9.6.6 SessionComputeBoundEntity()
This function computes the binding value for a session. The binding value for a reserved handle is the
handle itself. For all the other entities, the authValue at the time of binding is included to prevent
squatting. For those values, the Name and the authValue are concatenated into the bind buffer. If they
will not both fit, the will be overlapped by XORing bytes. If XOR is required, the bind value will be full.
520 void
521 SessionComputeBoundEntity(
8.9.6.7 SessionSetStartTime()
552 void
553 SessionSetStartTime(
554 SESSION *session // IN: the session to update
555 )
556 {
557 session->startTime = g_time;
558 session->epoch = g_timeEpoch;
559 session->timeout = 0;
560 }
8.9.6.8 SessionResetPolicyData()
This function is used to reset the policy data without changing the nonce or the start time of the session.
561 void
562 SessionResetPolicyData(
563 SESSION *session // IN: the session to reset
564 )
565 {
566 SESSION_ATTRIBUTES oldAttributes;
567 pAssert(session != NULL);
568
569 // Will need later
570 oldAttributes = session->attributes;
571
572 // No command
573 session->commandCode = 0;
574
8.9.6.9 SessionCapGetLoaded()
This function returns a list of handles of loaded session, started from input handle
Handle must be in valid loaded session handle range, but does not have to point to a loaded session.
602 TPMI_YES_NO
603 SessionCapGetLoaded(
604 TPMI_SH_POLICY handle, // IN: start handle
605 UINT32 count, // IN: count of returned handles
606 TPML_HANDLE *handleList // OUT: list of handle
607 )
608 {
609 TPMI_YES_NO more = NO;
610 UINT32 i;
611
612 pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION);
613
614 // Initialize output handle list
615 handleList->count = 0;
616
617 // The maximum count of handles we may return is MAX_CAP_HANDLES
618 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
619
620 // Iterate session context ID slots to get loaded session handles
621 for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
622 {
623 // If session is active
624 if(gr.contextArray[i] != 0)
625 {
626 // If session is loaded
8.9.6.10 SessionCapGetSaved()
This function returns a list of handles for saved session, starting at handle.
Handle must be in a valid handle range, but does not have to point to a saved session
656 TPMI_YES_NO
657 SessionCapGetSaved(
658 TPMI_SH_HMAC handle, // IN: start handle
659 UINT32 count, // IN: count of returned handles
660 TPML_HANDLE *handleList // OUT: list of handle
661 )
662 {
663 TPMI_YES_NO more = NO;
664 UINT32 i;
665
666 #ifdef TPM_HT_SAVED_SESSION
667 pAssert(HandleGetType(handle) == TPM_HT_SAVED_SESSION);
668 #else
669 pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION);
670 #endif
671
672 // Initialize output handle list
673 handleList->count = 0;
674
675 // The maximum count of handles we may return is MAX_CAP_HANDLES
676 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
677
678 // Iterate session context ID slots to get loaded session handles
8.9.6.11 SessionCapGetLoadedNumber()
This function return the number of authorization sessions currently loaded into TPM RAM.
707 UINT32
708 SessionCapGetLoadedNumber(
709 void
710 )
711 {
712 return MAX_LOADED_SESSIONS - s_freeSessionSlots;
713 }
8.9.6.12 SessionCapGetLoadedAvail()
This function returns the number of additional authorization sessions, of any type, that could be loaded
into TPM RAM.
NOTE: In other implementations, this number may just be an estimate. The only requirement for the estimate is, if it is
one or more, then at least one session must be loadable.
714 UINT32
715 SessionCapGetLoadedAvail(
716 void
717 )
718 {
719 return s_freeSessionSlots;
720 }
8.9.6.13 SessionCapGetActiveNumber()
This function returns the number of active authorization sessions currently being tracked by the TPM.
721 UINT32
722 SessionCapGetActiveNumber(
723 void
724 )
725 {
726 UINT32 i;
727 UINT32 num = 0;
728
729 // Iterate the context array to find the number of non-zero slots
730 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
731 {
732 if(gr.contextArray[i] != 0) num++;
733 }
734
735 return num;
736 }
8.9.6.14 SessionCapGetActiveAvail()
This function returns the number of additional authorization sessions, of any type, that could be created.
This not the number of slots for sessions, but the number of additional sessions that the TPM is capable
of tracking.
737 UINT32
738 SessionCapGetActiveAvail(
739 void
740 )
741 {
742 UINT32 i;
743 UINT32 num = 0;
744
745 // Iterate the context array to find the number of zero slots
746 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
747 {
748 if(gr.contextArray[i] == 0) num++;
749 }
750
751 return num;
752 }
8.10 Time.c
8.10.1 Introduction
This file contains the functions relating to the TPM's time functions including the interface to the
implementation-specific time functions.
8.10.2 Includes
1 #include "Tpm.h"
2 #include "PlatformClock.h"
8.10.3 Functions
8.10.3.1 TimePowerOn()
3 void
4 TimePowerOn(
5 void
6 )
7 {
8 g_time = _plat__TimerRead();
9 }
8.10.3.2 TimeNewEpoch()
This function does the processing to generate a new time epoch nonce and set NV for update. This
function is only called when NV is known to be available and the clock is running. The epoch is updated
to persistent data.
10 static void
11 TimeNewEpoch(
12 void
13 )
14 {
15 #if CLOCK_STOPS
16 CryptRandomGenerate(sizeof(CLOCK_NONCE), (BYTE *)&g_timeEpoch);
17 #else
18 // if the epoch is kept in NV, update it.
19 gp.timeEpoch++;
20 NV_SYNC_PERSISTENT(timeEpoch);
21 #endif
22 // Clean out any lingering state
23 _plat__TimerWasStopped();
24 }
8.10.3.3 TimeStartup()
This function updates the resetCount and restartCount components of TPMS_CLOCK_INFO structure at
TPM2_Startup().
Family “2.0” TCG Published Page 393
Level 00 Revision 01.59 Copyright © TCG 2006-2020 November 8, 2019
Trusted Platform Module Library Part 4: Supporting Routines
This function will deal with the deferred creation of a new epoch. TimeUpdateToCurrent() will not start a
new epoch even if one is due when TPM_Startup() has not been run. This is because the state of NV is
not known until startup completes. When Startup is done, then it will create the epoch nonce to complete
the initializations by calling this function.
25 BOOL
26 TimeStartup(
27 STARTUP_TYPE type // IN: start up type
28 )
29 {
30 NOT_REFERENCED(type);
31 // If the previous cycle is orderly shut down, the value of the safe bit
32 // the same as previously saved. Otherwise, it is not safe.
33 if(!NV_IS_ORDERLY)
34 go.clockSafe = NO;
35 return TRUE;
36 }
8.10.3.4 TimeClockUpdate()
This function updates go.clock. If newTime requires an update of NV, then NV is checked for availability.
If it is not available or is rate limiting, then go.clock is not updated and the function returns an error. If
newTime would not cause an NV write, then go.clock is updated. If an NV write occurs, then go.safe is
SET.
37 void
38 TimeClockUpdate(
39 UINT64 newTime // IN: New time value in mS.
40 )
41 {
42 #define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1)
43
44 // Check to see if the update will cause a need for an nvClock update
45 if((newTime | CLOCK_UPDATE_MASK) > (go.clock | CLOCK_UPDATE_MASK))
46 {
47 pAssert(g_NvStatus == TPM_RC_SUCCESS);
48
49 // Going to update the NV time state so SET the safe flag
50 go.clockSafe = YES;
51
52 // update the time
53 go.clock = newTime;
54
55 NvWrite(NV_ORDERLY_DATA, sizeof(go), &go);
56 }
57 else
58 // No NV update needed so just update
59 go.clock = newTime;
60
61 }
8.10.3.5 TimeUpdate()
This function is used to update the time and clock values. If the TPM has run TPM2_Startup(), this
function is called at the start of each command. If the TPM has not run TPM2_Startup(), this is called from
TPM2_Startup() to get the clock values initialized. It is not called on command entry because, in this
implementation, the go structure is not read from NV until TPM2_Startup(). The reason for this is that the
initialization code (_TPM_Init()) may run before NV is accessible.
62 void
63 TimeUpdate(
64 void
65 )
66 {
67 UINT64 elapsed;
68 //
69 // Make sure that we consume the current _plat__TimerWasStopped() state.
70 if(_plat__TimerWasStopped())
71 {
72 TimeNewEpoch();
73 }
74 // Get the difference between this call and the last time we updated the tick
75 // timer.
76 elapsed = _plat__TimerRead() - g_time;
77 // Don't read +
78 g_time += elapsed;
79
80 // Don't need to check the result because it has to be success because have
81 // already checked that NV is available.
82 TimeClockUpdate(go.clock + elapsed);
83
84 // Call self healing logic for dictionary attack parameters
85 DASelfHeal();
86 }
8.10.3.6 TimeUpdateToCurrent()
This function updates the Time and Clock in the global TPMS_TIME_INFO structure.
In this implementation, Time and Clock are updated at the beginning of each command and the values
are unchanged for the duration of the command.
Because Clock updates may require a write to NV memory, Time and Clock are not allowed to advance if
NV is not available. When clock is not advancing, any function that uses Clock will fail and return
TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE.
This implementation does not do rate limiting. If the implementation does do rate limiting, then the Clock
update should not be inhibited even when doing rate limiting.
87 void
88 TimeUpdateToCurrent(
89 void
90 )
91 {
92 // Can't update time during the dark interval or when rate limiting so don't
93 // make any modifications to the internal clock value. Also, defer any clock
94 // processing until TPM has run TPM2_Startup()
95 if(!NV_IS_AVAILABLE || !TPMIsStarted())
96 return;
97
98 TimeUpdate();
99 }
8.10.3.7 TimeSetAdjustRate()
100 void
101 TimeSetAdjustRate(
102 TPM_CLOCK_ADJUST adjust // IN: adjust constant
103 )
104 {
105 switch(adjust)
106 {
8.10.3.8 TimeGetMarshaled()
This function is used to access TPMS_TIME_INFO in canonical form. The function collects the time
information and marshals it into dataBuffer and returns the marshaled size
134 UINT16
135 TimeGetMarshaled(
136 TIME_INFO *dataBuffer // OUT: result buffer
137 )
138 {
139 TPMS_TIME_INFO timeInfo;
140
141 // Fill TPMS_TIME_INFO structure
142 timeInfo.time = g_time;
143 TimeFillInfo(&timeInfo.clockInfo);
144
145 // Marshal TPMS_TIME_INFO to canonical form
146 return TPMS_TIME_INFO_Marshal(&timeInfo, (BYTE **)&dataBuffer, NULL);
147 }
8.10.3.9 TimeFillInfo
148 void
149 TimeFillInfo(
150 TPMS_CLOCK_INFO *clockInfo
151 )
152 {
153 clockInfo->clock = go.clock;
154 clockInfo->resetCount = gp.resetCount;
155 clockInfo->restartCount = gr.restartCount;
156
157 // If NV is not available, clock stopped advancing and the value reported is
158 // not "safe".
159 if(NV_IS_AVAILABLE)
160 clockInfo->safe = go.clockSafe;
161 else
162 clockInfo->safe = NO;
163
164 return;
165 }
9 Support
9.1 AlgorithmCap.c
9.1.1 Description
This file contains the algorithm property definitions for the algorithms and the code for the
TPM2_GetCapability() to return the algorithm properties.
1 #include "Tpm.h"
2 typedef struct
3 {
4 TPM_ALG_ID algID;
5 TPMA_ALGORITHM attributes;
6 } ALGORITHM;
7 static const ALGORITHM s_algorithms[] =
8 {
9 // The entries in this table need to be in ascending order but the table doesn't
10 // need to be full (gaps are allowed). One day, a tool might exist to fill in the
11 // table from the TPM_ALG description
12 #if ALG_RSA
13 {TPM_ALG_RSA, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 1, 0, 0, 0, 0, 0)},
14 #endif
15 #if ALG_TDES
16 {TPM_ALG_TDES, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 0, 0, 0)},
17 #endif
18 #if ALG_SHA1
19 {TPM_ALG_SHA1, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 0, 0)},
20 #endif
21
22 {TPM_ALG_HMAC, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 1, 0, 0, 0)},
23
24 #if ALG_AES
25 {TPM_ALG_AES, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 0, 0, 0)},
26 #endif
27 #if ALG_MGF1
28 {TPM_ALG_MGF1, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 1, 0)},
29 #endif
30
31 {TPM_ALG_KEYEDHASH, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 1, 0, 1, 1, 0, 0)},
32
33 #if ALG_XOR
34 {TPM_ALG_XOR, TPMA_ALGORITHM_INITIALIZER(0, 1, 1, 0, 0, 0, 0, 0, 0)},
35 #endif
36
37 #if ALG_SHA256
38 {TPM_ALG_SHA256, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 0, 0)},
39 #endif
40 #if ALG_SHA384
41 {TPM_ALG_SHA384, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 0, 0)},
42 #endif
43 #if ALG_SHA512
44 {TPM_ALG_SHA512, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 0, 0)},
45 #endif
46 #if ALG_SM3_256
47 {TPM_ALG_SM3_256, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 0, 0)},
48 #endif
49 #if ALG_SM4
50 {TPM_ALG_SM4, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 0, 0, 0)},
51 #endif
52 #if ALG_RSASSA
53 {TPM_ALG_RSASSA, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 0, 0)},
54 #endif
55 #if ALG_RSAES
56 {TPM_ALG_RSAES, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 0, 1, 0, 0)},
57 #endif
58 #if ALG_RSAPSS
59 {TPM_ALG_RSAPSS, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 0, 0)},
60 #endif
61 #if ALG_OAEP
62 {TPM_ALG_OAEP, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 0, 1, 0, 0)},
63 #endif
64 #if ALG_ECDSA
65 {TPM_ALG_ECDSA, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 1, 0)},
66 #endif
67 #if ALG_ECDH
68 {TPM_ALG_ECDH, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 0, 0, 1, 0)},
69 #endif
70 #if ALG_ECDAA
71 {TPM_ALG_ECDAA, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 0, 0)},
72 #endif
73 #if ALG_SM2
74 {TPM_ALG_SM2, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 1, 0)},
75 #endif
76 #if ALG_ECSCHNORR
77 {TPM_ALG_ECSCHNORR, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 1, 0, 0, 0)},
78 #endif
79 #if ALG_ECMQV
80 {TPM_ALG_ECMQV, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 0, 0, 0, 0, 1, 0)},
81 #endif
82 #if ALG_KDF1_SP800_56A
83 {TPM_ALG_KDF1_SP800_56A, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 1, 0)},
84 #endif
85 #if ALG_KDF2
86 {TPM_ALG_KDF2, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 1, 0)},
87 #endif
88 #if ALG_KDF1_SP800_108
89 {TPM_ALG_KDF1_SP800_108, TPMA_ALGORITHM_INITIALIZER(0, 0, 1, 0, 0, 0, 0, 1, 0)},
90 #endif
91 #if ALG_ECC
92 {TPM_ALG_ECC, TPMA_ALGORITHM_INITIALIZER(1, 0, 0, 1, 0, 0, 0, 0, 0)},
93 #endif
94
95 {TPM_ALG_SYMCIPHER, TPMA_ALGORITHM_INITIALIZER(0, 0, 0, 1, 0, 0, 0, 0, 0)},
96
97 #if ALG_CAMELLIA
98 {TPM_ALG_CAMELLIA, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 0, 0, 0)},
99 #endif
100 #if ALG_CMAC
101 {TPM_ALG_CMAC, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 1, 0, 0, 0)},
102 #endif
103 #if ALG_CTR
104 {TPM_ALG_CTR, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 1, 0, 0)},
105 #endif
106 #if ALG_OFB
107 {TPM_ALG_OFB, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 1, 0, 0)},
108 #endif
109 #if ALG_CBC
110 {TPM_ALG_CBC, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 1, 0, 0)},
111 #endif
112 #if ALG_CFB
113 {TPM_ALG_CFB, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 1, 0, 0)},
114 #endif
115 #if ALG_ECB
116 {TPM_ALG_ECB, TPMA_ALGORITHM_INITIALIZER(0, 1, 0, 0, 0, 0, 1, 0, 0)},
117 #endif
118 };
9.1.3 AlgorithmCapGetImplemented()
119 TPMI_YES_NO
120 AlgorithmCapGetImplemented(
121 TPM_ALG_ID algID, // IN: the starting algorithm ID
122 UINT32 count, // IN: count of returned algorithms
123 TPML_ALG_PROPERTY *algList // OUT: algorithm list
124 )
125 {
126 TPMI_YES_NO more = NO;
127 UINT32 i;
128 UINT32 algNum;
129
130 // initialize output algorithm list
131 algList->count = 0;
132
133 // The maximum count of algorithms we may return is MAX_CAP_ALGS.
134 if(count > MAX_CAP_ALGS)
135 count = MAX_CAP_ALGS;
136
137 // Compute how many algorithms are defined in s_algorithms array.
138 algNum = sizeof(s_algorithms) / sizeof(s_algorithms[0]);
139
140 // Scan the implemented algorithm list to see if there is a match to 'algID'.
141 for(i = 0; i < algNum; i++)
142 {
143 // If algID is less than the starting algorithm ID, skip it
144 if(s_algorithms[i].algID < algID)
145 continue;
146 if(algList->count < count)
147 {
148 // If we have not filled up the return list, add more algorithms
149 // to it
150 algList->algProperties[algList->count].alg = s_algorithms[i].algID;
151 algList->algProperties[algList->count].algProperties =
152 s_algorithms[i].attributes;
153 algList->count++;
154 }
155 else
156 {
157 // If the return list is full but we still have algorithms
158 // available, report this and stop scanning.
159 more = YES;
160 break;
161 }
162 }
163
164 return more;
165 }
9.1.4 AlgorithmGetImplementedVector()
166 LIB_EXPORT
167 void
168 AlgorithmGetImplementedVector(
169 ALGORITHM_VECTOR *implemented // OUT: the implemented bits are SET
170 )
171 {
172 int index;
173
174 // Nothing implemented until we say it is
175 MemorySet(implemented, 0, sizeof(ALGORITHM_VECTOR));
176
177 for(index = (sizeof(s_algorithms) / sizeof(s_algorithms[0])) - 1;
178 index >= 0;
179 index--)
180 SET_BIT(s_algorithms[index].algID, *implemented);
181 return;
182 }
9.2 Bits.c
9.2.1 Introduction
This file contains bit manipulation routines. They operate on bit arrays.
The 0th bit in the array is the right-most bit in the 0th octet in the array.
NOTE: If pAssert() is defined, the functions will assert if the indicated bit number is outside of the range of bArray. How
the assert is handled is implementation dependent.
9.2.2 Includes
1 #include "Tpm.h"
9.2.3 Functions
9.2.3.1 TestBit()
2 BOOL
3 TestBit(
4 unsigned int bitNum, // IN: number of the bit in 'bArray'
5 BYTE *bArray, // IN: array containing the bits
6 unsigned int bytesInArray // IN: size in bytes of 'bArray'
7 )
8 {
9 pAssert(bytesInArray > (bitNum >> 3));
10 return((bArray[bitNum >> 3] & (1 << (bitNum & 7))) != 0);
11 }
9.2.3.2 SetBit()
12 void
13 SetBit(
14 unsigned int bitNum, // IN: number of the bit in 'bArray'
15 BYTE *bArray, // IN: array containing the bits
16 unsigned int bytesInArray // IN: size in bytes of 'bArray'
17 )
18 {
19 pAssert(bytesInArray > (bitNum >> 3));
20 bArray[bitNum >> 3] |= (1 << (bitNum & 7));
21 }
9.2.3.3 ClearBit()
22 void
23 ClearBit(
24 unsigned int bitNum, // IN: number of the bit in 'bArray'.
25 BYTE *bArray, // IN: array containing the bits
26 unsigned int bytesInArray // IN: size in bytes of 'bArray'
27 )
28 {
29 pAssert(bytesInArray > (bitNum >> 3));
30 bArray[bitNum >> 3] &= ~(1 << (bitNum & 7));
31 }
9.3 CommandCodeAttributes.c
9.3.1 Introduction
This file contains the functions for testing various command properties.
1 #include "Tpm.h"
2 #include "CommandCodeAttributes_fp.h"
3 #ifndef CC_VEND
4 #define CC_VEND (TPM_CC)(0x20000000)
5 #endif
6 typedef UINT16 ATTRIBUTE_TYPE;
The following file is produced from the command tables in part 3 of the specification. It defines the
attributes for each of the commands.
NOTE: This file is currently produced by an automated process. Files produced from Part 2 or Part 3 tables through
automated processes are not included in the specification so that there is no ambiguity about the table
containing the information being the normative definition.
7 #define _COMMAND_CODE_ATTRIBUTES_
8 #include "CommandAttributeData.h"
9.3.3.1 NextImplementedIndex()
This function is used when the lists are not compressed. In a compressed list, only the implemented
commands are present. So, a search might find a value but that value may not be implemented. This
function checks to see if the input commandIndex points to an implemented command and, if not, it
searches upwards until it finds one. When the list is compressed, this function gets defined as a no-op.
9 #if !COMPRESSED_LISTS
10 static COMMAND_INDEX
11 NextImplementedIndex(
12 COMMAND_INDEX commandIndex
13 )
14 {
15 for(;commandIndex < COMMAND_COUNT; commandIndex++)
16 {
17 if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED)
18 return commandIndex;
19 }
20 return UNIMPLEMENTED_COMMAND_INDEX;
21 }
22 #else
23 #define NextImplementedIndex(x) (x)
24 #endif
9.3.3.2 GetClosestCommandIndex()
This function returns the command index for the command with a value that is equal to or greater than the
input value
25 COMMAND_INDEX
26 GetClosestCommandIndex(
27 TPM_CC commandCode // IN: the command code to start at
28 )
29 {
30 BOOL vendor = (commandCode & CC_VEND) != 0;
31 COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode;
32
33 // The commandCode is a UINT32 and the search index is UINT16. We are going to
34 // search for a match but need to make sure that the commandCode value is not
35 // out of range. To do this, need to clear the vendor bit of the commandCode
36 // (if set) and compare the result to the 16-bit searchIndex value. If it is
37 // out of range, indicate that the command is not implemented
38 if((commandCode & ~CC_VEND) != searchIndex)
39 return UNIMPLEMENTED_COMMAND_INDEX;
40
41 // if there is at least one vendor command, the last entry in the array will
42 // have the v bit set. If the input commandCode is larger than the last
43 // vendor-command, then it is out of range.
44 if(vendor)
45 {
46 #if VENDOR_COMMAND_ARRAY_SIZE > 0
47 COMMAND_INDEX commandIndex;
48 COMMAND_INDEX min;
49 COMMAND_INDEX max;
50 int diff;
51 #if LIBRARY_COMMAND_ARRAY_SIZE == COMMAND_COUNT
52 #error "Constants are not consistent."
53 #endif
54 // Check to see if the value is equal to or below the minimum
55 // entry.
56 // Note: Put this check first so that the typical case of only one vendor-
57 // specific command doesn't waste any more time.
58 if(GET_ATTRIBUTE(s_ccAttr[LIBRARY_COMMAND_ARRAY_SIZE], TPMA_CC,
59 commandIndex) >= searchIndex)
60 {
61 // the vendor array is always assumed to be packed so there is
62 // no need to check to see if the command is implemented
63 return LIBRARY_COMMAND_ARRAY_SIZE;
64 }
65 // See if this is out of range on the top
66 if(GET_ATTRIBUTE(s_ccAttr[COMMAND_COUNT - 1], TPMA_CC, commandIndex)
67 < searchIndex)
68 {
69 return UNIMPLEMENTED_COMMAND_INDEX;
70 }
71 commandIndex = UNIMPLEMENTED_COMMAND_INDEX; // Needs initialization to keep
72 // compiler happy
73 min = LIBRARY_COMMAND_ARRAY_SIZE; // first vendor command
74 max = COMMAND_COUNT - 1; // last vendor command
75 diff = 1; // needs initialization to keep
76 // compiler happy
77 while(min <= max)
78 {
9.3.3.3 CommandCodeToComandIndex()
This function returns the index in the various attributes arrays of the command.
179 COMMAND_INDEX
180 CommandCodeToCommandIndex(
181 TPM_CC commandCode // IN: the command code to look up
182 )
183 {
184 // Extract the low 16-bits of the command code to get the starting search index
185 COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode;
186 BOOL vendor = (commandCode & CC_VEND) != 0;
187 COMMAND_INDEX commandIndex;
188 #if !COMPRESSED_LISTS
189 if(!vendor)
190 {
191 commandIndex = searchIndex - (COMMAND_INDEX)s_ccAttr[0].commandIndex;
192 // Check for out of range or unimplemented.
193 // Note, since a COMMAND_INDEX is unsigned, if searchIndex is smaller than
194 // the lowest value of command, it will become a 'negative' number making
195 // it look like a large unsigned number, this will cause it to fail
196 // the unsigned check below.
197 if(commandIndex >= LIBRARY_COMMAND_ARRAY_SIZE
9.3.3.4 GetNextCommandIndex()
217 COMMAND_INDEX
218 GetNextCommandIndex(
219 COMMAND_INDEX commandIndex // IN: the starting index
220 )
221 {
222 while(++commandIndex < COMMAND_COUNT)
223 {
224 #if !COMPRESSED_LISTS
225 if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED)
226 #endif
227 return commandIndex;
228 }
229 return UNIMPLEMENTED_COMMAND_INDEX;
230 }
9.3.3.5 GetCommandCode()
This function returns the commandCode associated with the command index
231 TPM_CC
232 GetCommandCode(
233 COMMAND_INDEX commandIndex // IN: the command index
234 )
235 {
236 TPM_CC commandCode = GET_ATTRIBUTE(s_ccAttr[commandIndex],
237 TPMA_CC, commandIndex);
238 if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
239 commandCode += CC_VEND;
240 return commandCode;
241 }
9.3.3.6 CommandAuthRole()
242 AUTH_ROLE
243 CommandAuthRole(
244 COMMAND_INDEX commandIndex, // IN: command index
245 UINT32 handleIndex // IN: handle index (zero based)
246 )
247 {
248 if(0 == handleIndex)
249 {
250 // Any authorization role set?
251 COMMAND_ATTRIBUTES properties = s_commandAttributes[commandIndex];
252
253 if(properties & HANDLE_1_USER)
254 return AUTH_USER;
255 if(properties & HANDLE_1_ADMIN)
256 return AUTH_ADMIN;
257 if(properties & HANDLE_1_DUP)
258 return AUTH_DUP;
259 }
260 else if(1 == handleIndex)
261 {
262 if(s_commandAttributes[commandIndex] & HANDLE_2_USER)
263 return AUTH_USER;
264 }
265 return AUTH_NONE;
266 }
9.3.3.7 EncryptSize()
This function returns the size of the decrypt size field. This function returns 0 if encryption is not allowed
267 int
268 EncryptSize(
269 COMMAND_INDEX commandIndex // IN: command index
270 )
271 {
272 return ((s_commandAttributes[commandIndex] & ENCRYPT_2) ? 2 :
273 (s_commandAttributes[commandIndex] & ENCRYPT_4) ? 4 : 0);
274 }
9.3.3.8 DecryptSize()
This function returns the size of the decrypt size field. This function returns 0 if decryption is not allowed
275 int
276 DecryptSize(
277 COMMAND_INDEX commandIndex // IN: command index
278 )
279 {
280 return ((s_commandAttributes[commandIndex] & DECRYPT_2) ? 2 :
281 (s_commandAttributes[commandIndex] & DECRYPT_4) ? 4 : 0);
282 }
9.3.3.9 IsSessionAllowed()
283 BOOL
284 IsSessionAllowed(
285 COMMAND_INDEX commandIndex // IN: the command to be checked
286 )
287 {
288 return ((s_commandAttributes[commandIndex] & NO_SESSIONS) == 0);
289 }
9.3.3.10 IsHandleInResponse()
290 BOOL
291 IsHandleInResponse(
292 COMMAND_INDEX commandIndex
293 )
294 {
295 return ((s_commandAttributes[commandIndex] & R_HANDLE) != 0);
296 }
9.3.3.11 IsWriteOperation()
Checks to see if an operation will write to an NV Index and is subject to being blocked by read-lock
297 BOOL
298 IsWriteOperation(
299 COMMAND_INDEX commandIndex // IN: Command to check
300 )
301 {
302 #ifdef WRITE_LOCK
303 return ((s_commandAttributes[commandIndex] & WRITE_LOCK) != 0);
304 #else
305 if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
306 {
307 switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex))
308 {
309 case TPM_CC_NV_Write:
310 #if CC_NV_Increment
311 case TPM_CC_NV_Increment:
312 #endif
313 #if CC_NV_SetBits
314 case TPM_CC_NV_SetBits:
315 #endif
316 #if CC_NV_Extend
317 case TPM_CC_NV_Extend:
318 #endif
319 #if CC_AC_Send
320 case TPM_CC_AC_Send:
321 #endif
322 // NV write lock counts as a write operation for authorization purposes.
323 // We check to see if the NV is write locked before we do the
324 // authorization. If it is locked, we fail the command early.
325 case TPM_CC_NV_WriteLock:
326 return TRUE;
327 default:
328 break;
329 }
330 }
331 return FALSE;
332 #endif
333 }
9.3.3.12 IsReadOperation()
Checks to see if an operation will write to an NV Index and is subject to being blocked by write-lock.
334 BOOL
335 IsReadOperation(
336 COMMAND_INDEX commandIndex // IN: Command to check
337 )
338 {
339 #ifdef READ_LOCK
340 return ((s_commandAttributes[commandIndex] & READ_LOCK) != 0);
341 #else
342
343 if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
344 {
345 switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex))
346 {
347 case TPM_CC_NV_Read:
348 case TPM_CC_PolicyNV:
349 case TPM_CC_NV_Certify:
350 // NV read lock counts as a read operation for authorization purposes.
351 // We check to see if the NV is read locked before we do the
352 // authorization. If it is locked, we fail the command early.
353 case TPM_CC_NV_ReadLock:
354 return TRUE;
355 default:
356 break;
357 }
358 }
359 return FALSE;
360 #endif
361 }
9.3.3.13 CommandCapGetCCList()
This function returns a list of implemented commands and command attributes starting from the
command in commandCode.
362 TPMI_YES_NO
363 CommandCapGetCCList(
364 TPM_CC commandCode, // IN: start command code
365 UINT32 count, // IN: maximum count for number of entries in
366 // 'commandList'
367 TPML_CCA *commandList // OUT: list of TPMA_CC
368 )
369 {
370 TPMI_YES_NO more = NO;
371 COMMAND_INDEX commandIndex;
372
373 // initialize output handle list count
374 commandList->count = 0;
375
376 for(commandIndex = GetClosestCommandIndex(commandCode);
377 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
378 commandIndex = GetNextCommandIndex(commandIndex))
379 {
380 #if !COMPRESSED_LISTS
381 // this check isn't needed for compressed lists.
382 if(!(s_commandAttributes[commandIndex] & IS_IMPLEMENTED))
383 continue;
384 #endif
385 if(commandList->count < count)
386 {
387 // If the list is not full, add the attributes for this command.
388 commandList->commandAttributes[commandList->count]
389 = s_ccAttr[commandIndex];
390 commandList->count++;
391 }
392 else
393 {
394 // If the list is full but there are more commands to report,
395 // indicate this and return.
396 more = YES;
397 break;
398 }
399 }
400 return more;
401 }
9.3.3.14 IsVendorCommand()
402 BOOL
403 IsVendorCommand(
404 COMMAND_INDEX commandIndex // IN: command index to check
405 )
406 {
407 return (IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V));
408 }
9.4 Entity.c
9.4.1 Description
The functions in this file are used for accessing properties for handles of various types. Functions in other
files require handles of a specific type but the functions in this file allow use of any handle type.
9.4.2 Includes
1 #include "Tpm.h"
9.4.3 Functions
9.4.3.1 EntityGetLoadStatus()
This function will check that all the handles access loaded entities.
2 TPM_RC
3 EntityGetLoadStatus(
4 COMMAND *command // IN/OUT: command parsing structure
5 )
6 {
7 UINT32 i;
8 TPM_RC result = TPM_RC_SUCCESS;
9 //
10 for(i = 0; i < command->handleNum; i++)
11 {
12 TPM_HANDLE handle = command->handles[i];
13 switch(HandleGetType(handle))
14 {
15 // For handles associated with hierarchies, the entity is present
16 // only if the associated enable is SET.
17 case TPM_HT_PERMANENT:
18 switch(handle)
19 {
20 case TPM_RH_OWNER:
21 if(!gc.shEnable)
22 result = TPM_RC_HIERARCHY;
23 break;
24
25 #ifdef VENDOR_PERMANENT
26 case VENDOR_PERMANENT:
27 #endif
28 case TPM_RH_ENDORSEMENT:
29 if(!gc.ehEnable)
30 result = TPM_RC_HIERARCHY;
31 break;
32 case TPM_RH_PLATFORM:
33 if(!g_phEnable)
34 result = TPM_RC_HIERARCHY;
35 break;
9.4.3.2 EntityGetAuthValue()
This function is used to access the authValue associated with a handle. This function assumes that the
handle references an entity that is accessible and the handle is not for a persistent objects. That is
EntityGetLoadStatus() should have been called. Also, the accessibility of the authValue should have been
verified by IsAuthValueAvailable().
This function copies the authorization value of the entity to auth.
141 UINT16
142 EntityGetAuthValue(
143 TPMI_DH_ENTITY handle, // IN: handle of entity
144 TPM2B_AUTH *auth // OUT: authValue of the entity
145 )
146 {
147 TPM2B_AUTH *pAuth = NULL;
148
149 auth->t.size = 0;
150
151 switch(HandleGetType(handle))
152 {
153 case TPM_HT_PERMANENT:
154 {
155 switch(handle)
156 {
157 case TPM_RH_OWNER:
158 // ownerAuth for TPM_RH_OWNER
159 pAuth = &gp.ownerAuth;
160 break;
161 case TPM_RH_ENDORSEMENT:
162 // endorsementAuth for TPM_RH_ENDORSEMENT
163 pAuth = &gp.endorsementAuth;
164 break;
165 // The ACT use platformAuth for auth
166 FOR_EACH_ACT(CASE_ACT_HANDLE)
167 case TPM_RH_PLATFORM:
168 // platformAuth for TPM_RH_PLATFORM
169 pAuth = &gc.platformAuth;
170 break;
171 case TPM_RH_LOCKOUT:
172 // lockoutAuth for TPM_RH_LOCKOUT
173 pAuth = &gp.lockoutAuth;
174 break;
175 case TPM_RH_NULL:
176 // nullAuth for TPM_RH_NULL. Return 0 directly here
177 return 0;
178 break;
179 #ifdef VENDOR_PERMANENT
180 case VENDOR_PERMANENT:
181 // vendor authorization value
182 pAauth = &g_platformUniqueDetails;
183 #endif
184 default:
185 // If any other permanent handle is present it is
186 // a code defect.
187 FAIL(FATAL_ERROR_INTERNAL);
188 break;
189 }
190 break;
191 }
192 case TPM_HT_TRANSIENT:
193 // authValue for an object
194 // A persistent object would have been copied into RAM
195 // and would have an transient object handle here.
196 {
197 OBJECT *object;
198
199 object = HandleToObject(handle);
200 // special handling if this is a sequence object
201 if(ObjectIsSequence(object))
202 {
203 pAuth = &((HASH_OBJECT *)object)->auth;
204 }
205 else
206 {
207 // Authorization is available only when the private portion of
208 // the object is loaded. The check should be made before
209 // this function is called
210 pAssert(object->attributes.publicOnly == CLEAR);
211 pAuth = &object->sensitive.authValue;
212 }
213 }
214 break;
215 case TPM_HT_NV_INDEX:
216 // authValue for an NV index
217 {
9.4.3.3 EntityGetAuthPolicy()
This function is used to access the authPolicy associated with a handle. This function assumes that the
handle references an entity that is accessible and the handle is not for a persistent objects. That is
EntityGetLoadStatus() should have been called. Also, the accessibility of the authPolicy should have
been verified by IsAuthPolicyAvailable().
This function copies the authorization policy of the entity to authPolicy.
The return value is the hash algorithm for the policy.
238 TPMI_ALG_HASH
239 EntityGetAuthPolicy(
240 TPMI_DH_ENTITY handle, // IN: handle of entity
241 TPM2B_DIGEST *authPolicy // OUT: authPolicy of the entity
242 )
243 {
244 TPMI_ALG_HASH hashAlg = TPM_ALG_NULL;
245 authPolicy->t.size = 0;
246
247 switch(HandleGetType(handle))
248 {
249 case TPM_HT_PERMANENT:
250 switch(handle)
251 {
252 case TPM_RH_OWNER:
253 // ownerPolicy for TPM_RH_OWNER
254 *authPolicy = gp.ownerPolicy;
255 hashAlg = gp.ownerAlg;
256 break;
257 case TPM_RH_ENDORSEMENT:
258 // endorsementPolicy for TPM_RH_ENDORSEMENT
259 *authPolicy = gp.endorsementPolicy;
260 hashAlg = gp.endorsementAlg;
261 break;
262 case TPM_RH_PLATFORM:
263 // platformPolicy for TPM_RH_PLATFORM
264 *authPolicy = gc.platformPolicy;
265 hashAlg = gc.platformAlg;
266 break;
267 case TPM_RH_LOCKOUT:
268 // lockoutPolicy for TPM_RH_LOCKOUT
269 *authPolicy = gp.lockoutPolicy;
9.4.3.4 EntityGetName()
312 TPM2B_NAME *
313 EntityGetName(
314 TPMI_DH_ENTITY handle, // IN: handle of entity
315 TPM2B_NAME *name // OUT: name of entity
316 )
317 {
318 switch(HandleGetType(handle))
319 {
320 case TPM_HT_TRANSIENT:
321 {
322 // Name for an object
323 OBJECT *object = HandleToObject(handle);
324 // an object with no nameAlg has no name
325 if(object->publicArea.nameAlg == TPM_ALG_NULL)
326 name->b.size = 0;
327 else
328 *name = object->name;
329 break;
330 }
331 case TPM_HT_NV_INDEX:
332 // Name for a NV index
333 NvGetNameByIndexHandle(handle, name);
334 break;
335 default:
336 // For all other types, the handle is the Name
337 name->t.size = sizeof(TPM_HANDLE);
338 UINT32_TO_BYTE_ARRAY(handle, name->t.name);
339 break;
340 }
341 return name;
342 }
9.4.3.5 EntityGetHierarchy()
343 TPMI_RH_HIERARCHY
344 EntityGetHierarchy(
345 TPMI_DH_ENTITY handle // IN :handle of entity
346 )
347 {
348 TPMI_RH_HIERARCHY hierarchy = TPM_RH_NULL;
349
350 switch(HandleGetType(handle))
351 {
352 case TPM_HT_PERMANENT:
353 // hierarchy for a permanent handle
354 switch(handle)
355 {
356 case TPM_RH_PLATFORM:
357 case TPM_RH_ENDORSEMENT:
358 case TPM_RH_NULL:
359 hierarchy = handle;
360 break;
361 // all other permanent handles are associated with the owner
362 // hierarchy. (should only be TPM_RH_OWNER and TPM_RH_LOCKOUT)
363 default:
364 hierarchy = TPM_RH_OWNER;
365 break;
366 }
367 break;
368 case TPM_HT_NV_INDEX:
369 // hierarchy for NV index
370 {
371 NV_INDEX *nvIndex = NvGetIndexInfo(handle, NULL);
372 pAssert(nvIndex != NULL);
373
374 // If only the platform can delete the index, then it is
375 // considered to be in the platform hierarchy, otherwise it
376 // is in the owner hierarchy.
377 if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV,
378 PLATFORMCREATE))
379 hierarchy = TPM_RH_PLATFORM;
380 else
381 hierarchy = TPM_RH_OWNER;
382 }
383 break;
384 case TPM_HT_TRANSIENT:
385 // hierarchy for an object
386 {
387 OBJECT *object;
388 object = HandleToObject(handle);
389 if(object->attributes.ppsHierarchy)
390 {
391 hierarchy = TPM_RH_PLATFORM;
392 }
393 else if(object->attributes.epsHierarchy)
394 {
395 hierarchy = TPM_RH_ENDORSEMENT;
396 }
397 else if(object->attributes.spsHierarchy)
398 {
399 hierarchy = TPM_RH_OWNER;
400 }
401 }
402 break;
403 case TPM_HT_PCR:
404 hierarchy = TPM_RH_OWNER;
405 break;
406 default:
407 FAIL(FATAL_ERROR_INTERNAL);
408 break;
409 }
410 // this is unreachable but it provides a return value for the default
411 // case which makes the complier happy
412 return hierarchy;
413 }
9.5 Global.c
9.5.1 Description
This file will instance the TPM variables that are not stack allocated. Descriptions of global variables are
in Global.h. There macro macro definitions that allows a variable to be instanced or simply defined as an
external variable. When global.h is included from this .c file, GLOBAL_C is defined and values are
instanced (and possibly initialized), but when global.h is included by any other file, they are simply defined
as external values. DO NOT DEFINE GLOBAL_C IN ANY OTHER FILE.
NOTE: This is a change from previous implementations where Global.h just contained the extern declaration and
values were instanced in this file. This change keeps the definition and instance in one file making maintenance
easier. The instanced data will still be in the global.obj file.
The OIDs.h file works in a way that is similar to the Global.h with the definition of the values in OIDs.h
such that they are instanced in global.obj. The macros that are defined in Global.h are used in OIDs.h in
the same way as they are in Global.h.
1 #define GLOBAL_C
2 #include "Tpm.h"
3 #include "OIDs.h"
4 #if CC_CertifyX509
5 # include "X509.h"
6 #endif // CC_CertifyX509
9.6 Handle.c
9.6.1 Description
This file contains the functions that return the type of a handle.
9.6.2 Includes
1 #include "Tpm.h"
9.6.3 Functions
9.6.3.1 HandleGetType()
This function returns the type of a handle which is the MSO of the handle.
2 TPM_HT
3 HandleGetType(
4 TPM_HANDLE handle // IN: a handle to be checked
5 )
6 {
7 // return the upper bytes of input data
8 return (TPM_HT)((handle & HR_RANGE_MASK) >> HR_SHIFT);
9 }
9.6.3.2 NextPermanentHandle()
This function returns the permanent handle that is equal to the input value or is the next higher value. If
there is no handle with the input value and there is no next higher value, it returns 0:
10 TPM_HANDLE
11 NextPermanentHandle(
12 TPM_HANDLE inHandle // IN: the handle to check
13 )
14 {
15 // If inHandle is below the start of the range of permanent handles
16 // set it to the start and scan from there
17 if(inHandle < TPM_RH_FIRST)
18 inHandle = TPM_RH_FIRST;
19 // scan from input value until we find an implemented permanent handle
20 // or go out of range
21 for(; inHandle <= TPM_RH_LAST; inHandle++)
22 {
23 switch(inHandle)
24 {
25 case TPM_RH_OWNER:
26 case TPM_RH_NULL:
27 case TPM_RS_PW:
28 case TPM_RH_LOCKOUT:
29 case TPM_RH_ENDORSEMENT:
30 case TPM_RH_PLATFORM:
31 case TPM_RH_PLATFORM_NV:
32 #ifdef VENDOR_PERMANENT
33 case VENDOR_PERMANENT:
34 #endif
35 // Each of the implemented ACT
36 #define ACT_IMPLEMENTED_CASE(N) \
37 case TPM_RH_ACT_##N:
38
39 FOR_EACH_ACT(ACT_IMPLEMENTED_CASE)
40
41 return inHandle;
42 break;
43 default:
44 break;
45 }
46 }
47 // Out of range on the top
48 return 0;
49 }
9.6.3.3 PermanentCapGetHandles()
This function returns a list of the permanent handles of PCR, started from handle. If handle is larger than
the largest permanent handle, an empty list will be returned with more set to NO.
50 TPMI_YES_NO
51 PermanentCapGetHandles(
52 TPM_HANDLE handle, // IN: start handle
53 UINT32 count, // IN: count of returned handles
54 TPML_HANDLE *handleList // OUT: list of handle
55 )
56 {
57 TPMI_YES_NO more = NO;
58 UINT32 i;
59
60 pAssert(HandleGetType(handle) == TPM_HT_PERMANENT);
61
62 // Initialize output handle list
63 handleList->count = 0;
64
65 // The maximum count of handles we may return is MAX_CAP_HANDLES
66 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
67
68 // Iterate permanent handle range
69 for(i = NextPermanentHandle(handle);
70 i != 0; i = NextPermanentHandle(i + 1))
71 {
72 if(handleList->count < count)
73 {
74 // If we have not filled up the return list, add this permanent
75 // handle to it
76 handleList->handle[handleList->count] = i;
77 handleList->count++;
78 }
79 else
80 {
81 // If the return list is full but we still have permanent handle
82 // available, report this and stop iterating
83 more = YES;
84 break;
85 }
86 }
87 return more;
88 }
9.6.3.4 PermanentHandleGetPolicy()
This function returns a list of the permanent handles of PCR, started from handle. If handle is larger than
the largest permanent handle, an empty list will be returned with more set to NO.
89 TPMI_YES_NO
90 PermanentHandleGetPolicy(
91 TPM_HANDLE handle, // IN: start handle
92 UINT32 count, // IN: max count of returned handles
93 TPML_TAGGED_POLICY *policyList // OUT: list of handle
94 )
95 {
96 TPMI_YES_NO more = NO;
97
98 pAssert(HandleGetType(handle) == TPM_HT_PERMANENT);
99
100 // Initialize output handle list
101 policyList->count = 0;
102
103 // The maximum count of policies we may return is MAX_TAGGED_POLICIES
104 if(count > MAX_TAGGED_POLICIES)
105 count = MAX_TAGGED_POLICIES;
106
107 // Iterate permanent handle range
108 for(handle = NextPermanentHandle(handle);
109 handle != 0;
110 handle = NextPermanentHandle(handle + 1))
111 {
112 TPM2B_DIGEST policyDigest;
113 TPM_ALG_ID policyAlg;
114 // Check to see if this permanent handle has a policy
115 policyAlg = EntityGetAuthPolicy(handle, &policyDigest);
116 if(policyAlg == TPM_ALG_ERROR)
117 continue;
118 if(policyList->count < count)
119 {
120 // If we have not filled up the return list, add this
121 // policy to the list;
122 policyList->policies[policyList->count].handle = handle;
123 policyList->policies[policyList->count].policyHash.hashAlg = policyAlg;
124 MemoryCopy(&policyList->policies[policyList->count].policyHash.digest,
125 policyDigest.t.buffer, policyDigest.t.size);
126 policyList->count++;
127 }
128 else
129 {
130 // If the return list is full but we still have permanent handle
131 // available, report this and stop iterating
132 more = YES;
133 break;
134 }
135 }
136 return more;
137 }
9.7 IoBuffers.c
This definition allows this module to see the values that are private to this module but kept in Global.c for
ease of state migration.
1 #define IO_BUFFER_C
2 #include "Tpm.h"
3 #include "IoBuffers_fp.h"
These buffers are set aside to hold command and response values. In this implementation, it is not
guaranteed that the code will stop accessing the s_actionInputBuffer before starting to put values in the
s_actionOutputBuffer so different buffers are required.
9.7.2.1 MemoryIoBufferAllocationReset()
4 void
5 MemoryIoBufferAllocationReset(
6 void
7 )
8 {
9 s_actionIoAllocation = 0;
10 }
9.7.2.2 MemoryIoBufferZero()
Function zeros the action I/O buffer at the end of a command. Calling this is not mandatory for proper
functionality.
11 void
12 MemoryIoBufferZero(
13 void
14 )
15 {
16 memset(s_actionIoBuffer, 0, s_actionIoAllocation);
17 }
9.7.2.3 MemoryGetInBuffer()
This function returns the address of the buffer into which the command parameters will be unmarshaled in
preparation for calling the command actions.
18 BYTE *
19 MemoryGetInBuffer(
20 UINT32 size // Size, in bytes, required for the input
21 // unmarshaling
22 )
23 {
24 pAssert(size <= sizeof(s_actionIoBuffer));
25 // In this implementation, a static buffer is set aside for the command action
26 // buffers. The buffer is shared between input and output. This is because
27 // there is no need to allocate for the worst case input and worst case output
9.7.2.4 MemoryGetOutBuffer()
This function returns the address of the buffer into which the command action code places its output
values.
36 BYTE *
37 MemoryGetOutBuffer(
38 UINT32 size // required size of the buffer
39 )
40 {
41 BYTE *retVal = (BYTE *)(&s_actionIoBuffer[s_actionIoAllocation / UoM]);
42 pAssert((size + s_actionIoAllocation) < (sizeof(s_actionIoBuffer)));
43 // In this implementation, a static buffer is set aside for the command action
44 // output buffer.
45 memset(retVal, 0, size);
46 s_actionIoAllocation += size;
47 return retVal;
48 }
9.7.2.5 IsLabelProperlyFormatted()
NOTE: this function is here because there was no better place for it.
49 BOOL
50 IsLabelProperlyFormatted(
51 TPM2B *x
52 )
53 {
54 return (((x)->size == 0) || ((x)->buffer[(x)->size - 1] == 0));
55 }
9.8 Locality.c
9.8.1 Includes
1 #include "Tpm.h"
9.8.2 LocalityGetAttributes()
This function will convert a locality expressed as an integer into TPMA_LOCALITY form.
The function returns the locality attribute.
2 TPMA_LOCALITY
3 LocalityGetAttributes(
4 UINT8 locality // IN: locality value
5 )
6 {
7 TPMA_LOCALITY locality_attributes;
8 BYTE *localityAsByte = (BYTE *)&locality_attributes;
9
10 MemorySet(&locality_attributes, 0, sizeof(TPMA_LOCALITY));
11 switch(locality)
12 {
13 case 0:
14 SET_ATTRIBUTE(locality_attributes, TPMA_LOCALITY, TPM_LOC_ZERO);
15 break;
16 case 1:
17 SET_ATTRIBUTE(locality_attributes, TPMA_LOCALITY, TPM_LOC_ONE);
18 break;
19 case 2:
20 SET_ATTRIBUTE(locality_attributes, TPMA_LOCALITY, TPM_LOC_TWO);
21 break;
22 case 3:
23 SET_ATTRIBUTE(locality_attributes, TPMA_LOCALITY, TPM_LOC_THREE);
24 break;
25 case 4:
26 SET_ATTRIBUTE(locality_attributes, TPMA_LOCALITY, TPM_LOC_FOUR);
27 break;
28 default:
29 pAssert(locality > 31);
30 *localityAsByte = locality;
31 break;
32 }
33 return locality_attributes;
34 }
9.9 Manufacture.c
9.9.1 Description
This file contains the function that performs the manufacturing of the TPM in a simulated environment.
These functions should not be used outside of a manufacturing or simulation environment.
1 #define MANUFACTURE_C
2 #include "Tpm.h"
3 #include "TpmSizeChecks_fp.h"
9.9.3 Functions
9.9.3.1 TPM_Manufacture()
This function initializes the TPM values in preparation for the TPM's first use. This function will fail if
previously called. The TPM can be re-manufactured by calling TPM_Teardown() first and then calling this
function again.
4 LIB_EXPORT int
5 TPM_Manufacture(
6 int firstTime // IN: indicates if this is the first call from
7 // main()
8 )
9 {
10 TPM_SU orderlyShutdown;
11
12 #if RUNTIME_SIZE_CHECKS
13 // Call the function to verify the sizes of values that result from different
14 // compile options.
15 if(!TpmSizeChecks())
16 return -1;
17 #endif
18 #if LIBRARY_COMPATIBILITY_CHECK
19 // Make sure that the attached library performs as expected.
20 if(!MathLibraryCompatibilityCheck())
21 return -1;
22 #endif
23
24 // If TPM has been manufactured, return indication.
25 if(!firstTime && g_manufactured)
26 return 1;
27
28 // Do power on initializations of the cryptographic libraries.
29 CryptInit();
30
31 s_DAPendingOnNV = FALSE;
32
33 // initialize NV
34 NvManufacture();
35
36 // Clear the magic value in the DRBG state
37 go.drbgState.magic = 0;
38
39 CryptStartup(SU_RESET);
40
41 // default configuration for PCR
42 PCRSimStart();
43
44 // initialize pre-installed hierarchy data
45 // This should happen after NV is initialized because hierarchy data is
46 // stored in NV.
47 HierarchyPreInstall_Init();
48
49 // initialize dictionary attack parameters
50 DAPreInstall_Init();
51
52 // initialize PP list
53 PhysicalPresencePreInstall_Init();
54
55 // initialize command audit list
56 CommandAuditPreInstall_Init();
57
58 // first start up is required to be Startup(CLEAR)
59 orderlyShutdown = TPM_SU_CLEAR;
60 NV_WRITE_PERSISTENT(orderlyState, orderlyShutdown);
61
62 // initialize the firmware version
63 gp.firmwareV1 = FIRMWARE_V1;
64 #ifdef FIRMWARE_V2
65 gp.firmwareV2 = FIRMWARE_V2;
66 #else
67 gp.firmwareV2 = 0;
68 #endif
69 NV_SYNC_PERSISTENT(firmwareV1);
70 NV_SYNC_PERSISTENT(firmwareV2);
71
72 // initialize the total reset counter to 0
73 gp.totalResetCount = 0;
74 NV_SYNC_PERSISTENT(totalResetCount);
75
76 // initialize the clock stuff
77 go.clock = 0;
78 go.clockSafe = YES;
79
80 NvWrite(NV_ORDERLY_DATA, sizeof(ORDERLY_DATA), &go);
81
82 // Commit NV writes. Manufacture process is an artificial process existing
83 // only in simulator environment and it is not defined in the specification
84 // that what should be the expected behavior if the NV write fails at this
85 // point. Therefore, it is assumed the NV write here is always success and
86 // no return code of this function is checked.
87 NvCommit();
88
89 g_manufactured = TRUE;
90
91 return 0;
92 }
9.9.3.2 TPM_TearDown()
This function prepares the TPM for re-manufacture. It should not be implemented in anything other than a
simulated TPM.
In this implementation, all that is needs is to stop the cryptographic units and set a flag to indicate that the
TPM can be re-manufactured. This should be all that is necessary to start the manufacturing process
again.
93 LIB_EXPORT int
94 TPM_TearDown(
95 void
96 )
97 {
98 g_manufactured = FALSE;
99 return 0;
100 }
9.9.3.3 TpmEndSimulation()
This function is called at the end of the simulation run. It is used to provoke printing of any statistics that
might be needed.
9.10 Marshal.c
9.10.1 Introduction
1 TPM_RC
2 TPMI_DH_OBJECT_Unmarshal(TPMI_DH_OBJECT *target, BYTE **buffer, INT32 *size,
3 BOOL flag)
4 {
5 TPM_RC result;
6 result = TPM_HANDLE_Unmarshal((TPM_HANDLE *)target, buffer, size);
7 if(result != TPM_RC_SUCCESS)
8 return result;
9 if(*target == TPM_RH_NULL)
10 {
11 if(flag)
12 return TPM_RC_SUCCESS;
13 else
14 return TPM_RC_VALUE;
15 }
16 if(((*target < TRANSIENT_FIRST) || (*target > TRANSIENT_LAST))
17 &&((*target < PERSISTENT_FIRST) || (*target > PERSISTENT_LAST)))
18 return TPM_RC_VALUE;
19 return TPM_RC_SUCCESS;
20 }
NOTE The marshaling code does not do parameter checking, as the TPM is the source of the marshaling data .
1 UINT16
2 TPMI_DH_OBJECT_Marshal(TPMI_DH_OBJECT *source, BYTE **buffer, INT32 *size)
3 {
4 return UINT32_Marshal((UINT32 *)source, buffer, size);
5 }
An additional script is used to do the work that might be done by a linker or globally optimizing compiler. It
searches for functions like TPMI_DH_OBJECT_Marshal() that do nothing but call another function and
replaces the function with a #define.
When replacing the function with a #define, the #define is placed in marshal_fp.h and the function body is
removed from marshal.c.
1 TPM_RC
2 TPMU_PUBLIC_PARMS_Unmarshal(TPMU_PUBLIC_PARMS *target, BYTE **buffer, INT32 *size,
3 UINT32 selector)
4 {
5 switch(selector) {
6 #if ALG_KEYEDHASH
7 case TPM_ALG_KEYEDHASH:
8 return TPMS_KEYEDHASH_PARMS_Unmarshal(
9 (TPMS_KEYEDHASH_PARMS *)&(target->keyedHash), buffer, size);
10 #endif
11 #if ALG_SYMCIPHER
12 case TPM_ALG_SYMCIPHER:
13 return TPMT_SYM_DEF_OBJECT_Unmarshal(
14 (TPMT_SYM_DEF_OBJECT *)&(target->symDetail), buffer, size, FALSE);
15 #endif
16 #if ALG_RSA
17 case TPM_ALG_RSA:
18 return TPMS_RSA_PARMS_Unmarshal(
19 (TPMS_RSA_PARMS *)&(target->rsaDetail), buffer, size);
20 #endif
21 #if ALG_ECC
22 case TPM_ALG_ECC:
23 return TPMS_ECC_PARMS_Unmarshal(
24 (TPMS_ECC_PARMS *)&(target->eccDetail), buffer, size);
25 #endif
26 }
27 return TPM_RC_SELECTOR;
28 }
NOTE The #if/#endif directives are added whenever a value is dependent on an algorithm ID so that removing
the algorithm definition will remove the related code.
1 UINT16
2 TPMU_PUBLIC_PARMS_Marshal(TPMU_PUBLIC_PARMS *source, BYTE **buffer, INT32 *size,
3 UINT32 selector)
4 {
5 switch(selector) {
6 #if ALG_KEYEDHASH
7 case TPM_ALG_KEYEDHASH:
8 return TPMS_KEYEDHASH_PARMS_Marshal(
9 (TPMS_KEYEDHASH_PARMS *)&(source->keyedHash), buffer, size);
10 #endif
11 #if ALG_SYMCIPHER
12 case TPM_ALG_SYMCIPHER:
13 return TPMT_SYM_DEF_OBJECT_Marshal(
14 (TPMT_SYM_DEF_OBJECT *)&(source->symDetail), buffer, size);
15 #endif
16 #if ALG_RSA
17 case TPM_ALG_RSA:
18 return TPMS_RSA_PARMS_Marshal(
19 (TPMS_RSA_PARMS *)&(source->rsaDetail), buffer, size);
20 #endif
21 #if ALG_ECC
22 case TPM_ALG_ECC:
23 return TPMS_ECC_PARMS_Marshal(
24 (TPMS_ECC_PARMS *)&(source->eccDetail), buffer, size);
25 #endif
26 }
27 assert(1);
28 return 0;
29 }
For the marshaling and unmarshaling code, a value in the structure containing the union provides the
value used for selector. The example in the next section illustrates this.
objectAttributes TPMA_OBJECT attributes that, along with type, determine the manipulations of this
object
authPolicy TPM2B_DIGEST optional policy for using this key
The policy is computed using the nameAlg of the object.
NOTE shall be the Empty Buffer if no authorization policy is present
This structure is tagged (the first value indicates the structure type), and that tag is used to determine how
the parameters and unique fields are unmarshaled and marshaled. The use of the type for specifying the
union selector is emphasized below.
The unmarshaling code for the structure in the table above is:
1 TPM_RC
2 TPMT_PUBLIC_Unmarshal(TPMT_PUBLIC *target, BYTE **buffer, INT32 *size, BOOL flag)
3 {
4 TPM_RC result;
5 result = TPMI_ALG_PUBLIC_Unmarshal((TPMI_ALG_PUBLIC *)&(target->type),
6 buffer, size);
7 if(result != TPM_RC_SUCCESS)
8 return result;
9 result = TPMI_ALG_HASH_Unmarshal((TPMI_ALG_HASH *)&(target->nameAlg),
10 buffer, size, flag);
11 if(result != TPM_RC_SUCCESS)
12 return result;
13 result = TPMA_OBJECT_Unmarshal((TPMA_OBJECT *)&(target->objectAttributes),
14 buffer, size);
15 if(result != TPM_RC_SUCCESS)
16 return result;
17 result = TPM2B_DIGEST_Unmarshal((TPM2B_DIGEST *)&(target->authPolicy),
18 buffer, size);
19 if(result != TPM_RC_SUCCESS)
20 return result;
21
22 result = TPMU_PUBLIC_PARMS_Unmarshal((TPMU_PUBLIC_PARMS *)&(target->parameters),
23 buffer, size, );
24 if(result != TPM_RC_SUCCESS)
25 return result;
26
27 result = TPMU_PUBLIC_ID_Unmarshal((TPMU_PUBLIC_ID *)&(target->unique),
28 buffer, size, )
29 if(result != TPM_RC_SUCCESS)
30 return result;
31
32 return TPM_RC_SUCCESS;
33 }
1 UINT16
2 TPMT_PUBLIC_Marshal(TPMT_PUBLIC *source, BYTE **buffer, INT32 *size)
3 {
4 UINT16 result = 0;
5 result = (UINT16)(result + TPMI_ALG_PUBLIC_Marshal(
6 (TPMI_ALG_PUBLIC *)&(source->type), buffer, size));
7 result = (UINT16)(result + TPMI_ALG_HASH_Marshal(
8 (TPMI_ALG_HASH *)&(source->nameAlg), buffer, size))
9 ;
10 result = (UINT16)(result + TPMA_OBJECT_Marshal(
11 (TPMA_OBJECT *)&(source->objectAttributes), buffer, size));
12
13 result = (UINT16)(result + TPM2B_DIGEST_Marshal(
14 (TPM2B_DIGEST *)&(source->authPolicy), buffer, size));
15
16 result = (UINT16)(result + TPMU_PUBLIC_PARMS_Marshal(
17 (TPMU_PUBLIC_PARMS *)&(source->parameters), buffer, size,
18 ));
19
20 result = (UINT16)(result + TPMU_PUBLIC_ID_Marshal(
21 (TPMU_PUBLIC_ID *)&(source->unique), buffer, size,
22 ));
23
24 return result;
25 }
1 TPM_RC
2 TPML_DIGEST_Unmarshal(TPML_DIGEST *target, BYTE **buffer, INT32 *size)
3 {
4 TPM_RC result;
5 result = UINT32_Unmarshal((UINT32 *)&(target->count), buffer, size);
6 if(result != TPM_RC_SUCCESS)
7 return result;
8
9 if( (target->count < 2)) // This check is triggered by the {2:} notation
10 // on ‘count’
11 return TPM_RC_SIZE;
12
13 if((target->count) > 8) // This check is triggered by the {:8} notation
14 // on ‘digests’.
15 return TPM_RC_SIZE;
16
17 result = TPM2B_DIGEST_Array_Unmarshal((TPM2B_DIGEST *)(target->digests),
18 buffer, size, );
19 if(result != TPM_RC_SUCCESS)
20 return result;
21
22 return TPM_RC_SUCCESS;
23 }
The routine unmarshals a count value and passes that value to a routine that unmarshals an array of
TPM2B_DIGEST values. The unmarshaling code for the array is:
1 TPM_RC
2 TPM2B_DIGEST_Array_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size,
3 INT32 count)
4 {
5 TPM_RC result;
6 INT32 i;
7 for(i = 0; i < count; i++) {
8 result = TPM2B_DIGEST_Unmarshal(&target[i], buffer, size);
9 if(result != TPM_RC_SUCCESS)
10 return result;
11 }
12 return TPM_RC_SUCCESS;
13 }
14
Marshaling of the TPML_DIGEST uses a similar scheme with a structure specifying the number of
elements in an array and a subsequent call to a routine to marshal an array of that type.
1 UINT16
2 TPML_DIGEST_Marshal(TPML_DIGEST *source, BYTE **buffer, INT32 *size)
3 {
4 UINT16 result = 0;
5 result = (UINT16)(result + UINT32_Marshal((UINT32 *)&(source->count), buffer,
6 size));
7 result = (UINT16)(result + TPM2B_DIGEST_Array_Marshal(
8 (TPM2B_DIGEST *)(source->digests), buffer, size,
9 (INT32)(source->count)));
10
11 return result;
12 }
1 TPM_RC
2 TPM2B_DIGEST_Array_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size,
3 INT32 count)
4 {
5 TPM_RC result;
6 INT32 i;
7 for(i = 0; i < count; i++) {
8 result = TPM2B_DIGEST_Unmarshal(&target[i], buffer, size);
9 if(result != TPM_RC_SUCCESS)
10 return result;
11 }
12 return TPM_RC_SUCCESS;
13 }
A TPM2B structure is handled as a special case. The unmarshaling code is similar to what is shown in
9.10.5 but the unmarshaling/marshaling is to a union element. Each TPM2B is a union of two sized
buffers, one of which is type specific (the ‘t’ element) and the other is a generic value (the ‘b’ element).
This allows each of the TPM2B structures to have some inheritance property with all other TPM2B. The
purpose is to allow functions that have parameters that can be any TPM2B structure while allowing other
functions to be specific about the type of the TPM2B that is used. When the generic structure is allowed,
the input parameter would use the ‘b’ element and when the type-specific structure is required, the ‘t’
element is used.
When marshaling a TPM2B where the second member is a BYTE array, the size parameter indicates the
size of the array. The second member can also be a structure. In this case, the caller does not prefill the
size member. The marshaling code must marshal the structure and then back fill the calculated size.
1 TPM_RC
2 TPM2B_EVENT_Unmarshal(TPM2B_EVENT *target, BYTE **buffer, INT32 *size)
3 {
4 TPM_RC result;
5 result = UINT16_Unmarshal((UINT16 *)&(target->t.size), buffer, size);
6 if(result != TPM_RC_SUCCESS)
7 return result;
8 // if size equal to 0, the rest of the structure is a zero buffer
9 // so stop processing
10 if(target->t.size == 0)
11 return TPM_RC_SUCCESS;
12 if((target->t.size) > 1024) // This check is triggered by the {:1024}
13 // notation on ‘buffer’
14 return TPM_RC_SIZE;
15 result = BYTE_Array_Unmarshal((BYTE *)(target->t.buffer), buffer, size,
16 (INT32)(target->t.size));
17 if(result != TPM_RC_SUCCESS)
18 return result;
19 return TPM_RC_SUCCESS;
20 }
1 typedef union {
2 struct {
3 UINT16 size;
4 BYTE buffer[1024];
5 } t;
6 TPM2B b;
7 } TPM2B_EVENT;
9.10.7.1 TableMarshal.h
1 #ifndef _TABLE_DRIVEN_MARSHAL_H_
2 #define _TABLE_DRIVEN_MARSHAL_H_
These are the basic unmarshaling types. This is in the first byte of each structure descriptor that is
passed to Marshal()/Unmarshal() for processing.
3 #define UINT_MTYPE 0
4 #define VALUES_MTYPE (UINT_MTYPE + 1)
5 #define TABLE_MTYPE (VALUES_MTYPE + 1)
6 #define MIN_MAX_MTYPE (TABLE_MTYPE + 1)
7 #define ATTRIBUTES_MTYPE (MIN_MAX_MTYPE + 1)
8 #define STRUCTURE_MTYPE (ATTRIBUTES_MTYPE + 1)
9 #define TPM2B_MTYPE (STRUCTURE_MTYPE + 1)
10 #define TPM2BS_MTYPE (TPM2B_MTYPE + 1)
11 #define LIST_MTYPE (TPM2BS_MTYPE + 1) // TPML
12 #define ERROR_MTYPE (LIST_MTYPE + 1)
13 #define NULL_MTYPE (ERROR_MTYPE + 1)
14 #define COMPOSITE_MTYPE (NULL_MTYPE + 1)
A structure is used to hold the values that guide the marshaling/unmarshaling of each of the types. Each
structure has a name and an address. For a structure to define a TPMS_name, the structure is a
TPMS_name_MARSHAL_STRUCT and its index is TPMS_name_MARSHAL_INDEX. So, to get the
proper structure, use the associated marshal index. The marshal index is passed to Marshal() or
Unmarshal() and those functions look up the proper structure.
To handle structures that allow a null value, the upper bit of each marshal index indicates if the null value
is allowed. This is the NULL_FLAG. It is defined in TableMarshalIndex.h because it is needed by code
outside of the marshaling code. A structure will have a list of marshal indexes to indicate what to
unmarshal. When that index appears in a structure/union, the value will contain a flag to indicate that the
NULL_FLAG should be SET on the call to Unmarshal() to unmarshal the type. The caller simply takes the
entry and passes it to Unmarshal() to indicate that the NULL_FLAG is SET. There is also the opportunity
to SET the NULL_FLAG in the called structure if the NULL_FLAG was set in the call to the calling
structure. This is indicated by:
When looking up the value to marshal, the upper two bits of the marshal index are masked to yield the
actual index.
These are in used in anything that is an integer value. Theses would not be in structure modifier bytes
(they would be used in values in structures but not the STRUCTURE_MTYPE header.
When referencing a structure, this flag indicates if a null is to be propagated to the referenced structure or
type.
25 #define PROPAGATE_SHIFT 7
26 #define PROPAGATE_NULL (1 << PROPAGATE_SHIFT)
In a TPM2BS_MTYPE
Right now, there are two spare bits in the modifiers field. Within the descriptor word of each entry in a
StructMarsh_mst(), there is a selector field to determine which of the sub-types the entry represents and a
field that is used to reference another structure entry. This is a 6-bit field allowing a structure to have 64
entries. This should be more than enough as the structures are not that long. As of now, only 10-bits of
the descriptor word leaving room for expansion. These are the values used in a STRUCTURE_MTYPE to
identify the sub-type of the thing being processed
30 #define SIMPLE_STYPE 0
31 #define UNION_STYPE 1
32 #define ARRAY_STYPE 2
The code used GET_ to get the element type and the compiler uses SET_ to initialize the value. The
element type is the three bits (2:0).
When an entry is an array or union, this references the structure entry that contains the dimension or
selector value. The code then uses this number to look up the structure entry for that element to find out
what it and where is it in memory. When this is not a reference, it is a simple type and it could be used as
an array value or a union selector. When a simple value, this field contains the size of the associated
value (ONE_BYTES, TWO_BYTES ...) The entry size/number is 6 bits (13:8).
This determines if the null flag is propagated to this type. If generate, the NULL_FLAG is SET in the index
value. This flag is one bit (7)
This is used in all bit-field checks. These are used when a value that is checked is conditional (dependent
on the compilation). For example, if AES_128 is (NO), then the bit associated with AES_128 will be 0. In
some cases, the bit value is found by checking that the input is within the range of the table, and then
using the (val - min) value to index the bit. This would be used when verifying that a particular algorithm is
implemented. In other cases, there is a bit for each value in a table. For example, if checking the key
sizes, there is a list of possible key sizes allowed by the algorithm registry and a bit field to indicate if that
key size is allowed in the implementation. The smallest bit field has 32-bits 32-bits because it is
implemented as part of the values array of the structures that allow bit fields.
For a COMPOSITE_MTYPE, the qualifiers byte has an element size and count.
9.10.7.2 TableMarshalData.h
1 #ifndef _Table_Marshal_Data_
2 #define _Table_Marshal_Data_
The datatype descriptions for each type if needed in addition to the default types.
688 {
689 UINT8 marshalType;
690 UINT8 elements;
691 UINT16 values[6];
692 } TPMS_SIGNATURE_RSA_mst;
693 typedef const struct TPMS_SIGNATURE_ECC_mst
694 {
695 UINT8 marshalType;
696 UINT8 elements;
697 UINT16 values[9];
698 } TPMS_SIGNATURE_ECC_mst;
699 typedef struct TPMU_SIGNATURE_mst
700 {
701 BYTE countOfselectors;
702 BYTE modifiers;
703 UINT16 offsetOfUnmarshalTypes;
704 UINT32 selectors[8];
705 UINT16 marshalingTypes[8];
706 } TPMU_SIGNATURE_mst;
707 typedef const struct TPMT_SIGNATURE_mst
708 {
709 UINT8 marshalType;
710 UINT8 elements;
711 UINT16 values[6];
712 } TPMT_SIGNATURE_mst;
713 typedef struct TPMU_ENCRYPTED_SECRET_mst
714 {
715 BYTE countOfselectors;
716 BYTE modifiers;
717 UINT16 offsetOfUnmarshalTypes;
718 UINT32 selectors[4];
719 UINT16 marshalingTypes[4];
720 } TPMU_ENCRYPTED_SECRET_mst;
721 typedef const struct TPMI_ALG_PUBLIC_mst {
722 UINT8 marshalType;
723 UINT8 modifiers;
724 UINT8 errorCode;
725 UINT32 values[4];
726 } TPMI_ALG_PUBLIC_mst;
727 typedef struct TPMU_PUBLIC_ID_mst
728 {
729 BYTE countOfselectors;
730 BYTE modifiers;
731 UINT16 offsetOfUnmarshalTypes;
732 UINT32 selectors[4];
733 UINT16 marshalingTypes[4];
734 } TPMU_PUBLIC_ID_mst;
735 typedef const struct TPMS_KEYEDHASH_PARMS_mst
736 {
737 UINT8 marshalType;
738 UINT8 elements;
739 UINT16 values[3];
740 } TPMS_KEYEDHASH_PARMS_mst;
741 typedef const struct TPMS_ASYM_PARMS_mst
742 {
743 UINT8 marshalType;
744 UINT8 elements;
745 UINT16 values[6];
746 } TPMS_ASYM_PARMS_mst;
747 typedef const struct TPMS_RSA_PARMS_mst
748 {
749 UINT8 marshalType;
750 UINT8 elements;
751 UINT16 values[12];
752 } TPMS_RSA_PARMS_mst;
753 typedef const struct TPMS_ECC_PARMS_mst
754 {
755 UINT8 marshalType;
756 UINT8 elements;
757 UINT16 values[12];
758 } TPMS_ECC_PARMS_mst;
759 typedef struct TPMU_PUBLIC_PARMS_mst
760 {
761 BYTE countOfselectors;
762 BYTE modifiers;
763 UINT16 offsetOfUnmarshalTypes;
764 UINT32 selectors[4];
765 UINT16 marshalingTypes[4];
766 } TPMU_PUBLIC_PARMS_mst;
767 typedef const struct TPMT_PUBLIC_PARMS_mst
768 {
769 UINT8 marshalType;
770 UINT8 elements;
771 UINT16 values[6];
772 } TPMT_PUBLIC_PARMS_mst;
773 typedef const struct TPMT_PUBLIC_mst
774 {
775 UINT8 marshalType;
776 UINT8 elements;
777 UINT16 values[18];
778 } TPMT_PUBLIC_mst;
779 typedef struct TPMU_SENSITIVE_COMPOSITE_mst
780 {
781 BYTE countOfselectors;
782 BYTE modifiers;
783 UINT16 offsetOfUnmarshalTypes;
784 UINT32 selectors[4];
785 UINT16 marshalingTypes[4];
786 } TPMU_SENSITIVE_COMPOSITE_mst;
787 typedef const struct TPMT_SENSITIVE_mst
788 {
789 UINT8 marshalType;
790 UINT8 elements;
791 UINT16 values[12];
792 } TPMT_SENSITIVE_mst;
793 typedef const struct _PRIVATE_mst
794 {
795 UINT8 marshalType;
796 UINT8 elements;
797 UINT16 values[9];
798 } _PRIVATE_mst;
799 typedef const struct TPMS_ID_OBJECT_mst
800 {
801 UINT8 marshalType;
802 UINT8 elements;
803 UINT16 values[6];
804 } TPMS_ID_OBJECT_mst;
805 typedef const struct TPMS_NV_PIN_COUNTER_PARAMETERS_mst
806 {
807 UINT8 marshalType;
808 UINT8 elements;
809 UINT16 values[6];
810 } TPMS_NV_PIN_COUNTER_PARAMETERS_mst;
811 typedef const struct TPMS_NV_PUBLIC_mst
812 {
813 UINT8 marshalType;
814 UINT8 elements;
815 UINT16 values[15];
816 } TPMS_NV_PUBLIC_mst;
817 typedef const struct TPMS_CONTEXT_DATA_mst
818 {
819 UINT8 marshalType;
9.10.7.3 TableMarshalDefines.h
1 #ifndef _TABLE_MARSHAL_DEFINES_H_
2 #define _TABLE_MARSHAL_DEFINES_H_
3 #define NULL_SHIFT 15
4 #define NULL_FLAG (1 << NULL_SHIFT)
The range macro processes a min, max value and produces a values that is used in the computation to
see if something is within a range. The max value is (max-min). This lets the check for something (val)
within a range become: if((val - min) <= max) // passes if in range if((val - min) > max) // passes if not in
range This works because all values are converted to UINT32 values before the compare. For (val - min),
all values greater than or equal to val will become positive values with a value equal to min being zero.
This means that in an unsigned compare against 'max,' any value that is outside the range will appear to
be a number greater than max. The benefit of this operation is that this will work even if the input value is
a signed number as long as the input is sign extended.
This macro is like the offsetof macro but, instead of computing the offset of a structure element, it
computes the stride between elements that are in a structure array. This is used instead of sizeof()
because the sizeof() operator on a structure can return an implementation dependent value.
9 #define ARRAY_MARSHAL_ENTRY(TYPE) \
10 {(marshalIndex_t)TYPE##_MARSHAL_REF, (UINT16)STRIDE(TYPE)}
26 #define UINT8_MARSHAL_REF \
27 ((UINT16)(offsetof(MarshalData_st, UINT8_DATA)))
28 #define BYTE_MARSHAL_REF UINT8_MARSHAL_REF
29 #define TPM_HT_MARSHAL_REF UINT8_MARSHAL_REF
30 #define TPMA_LOCALITY_MARSHAL_REF UINT8_MARSHAL_REF
31 #define UINT16_MARSHAL_REF \
32 ((UINT16)(offsetof(MarshalData_st, UINT16_DATA)))
33 #define TPM_KEY_SIZE_MARSHAL_REF UINT16_MARSHAL_REF
34 #define TPM_KEY_BITS_MARSHAL_REF UINT16_MARSHAL_REF
35 #define TPM_ALG_ID_MARSHAL_REF UINT16_MARSHAL_REF
36 #define TPM_ST_MARSHAL_REF UINT16_MARSHAL_REF
37 #define UINT32_MARSHAL_REF \
38 ((UINT16)(offsetof(MarshalData_st, UINT32_DATA)))
39 #define TPM_ALGORITHM_ID_MARSHAL_REF UINT32_MARSHAL_REF
40 #define TPM_MODIFIER_INDICATOR_MARSHAL_REF UINT32_MARSHAL_REF
41 #define TPM_AUTHORIZATION_SIZE_MARSHAL_REF UINT32_MARSHAL_REF
42 #define TPM_PARAMETER_SIZE_MARSHAL_REF UINT32_MARSHAL_REF
43 #define TPM_SPEC_MARSHAL_REF UINT32_MARSHAL_REF
9.10.7.4 TableMarshalTypes.h
1 #ifndef _TABLE_MARSHAL_TYPES_H_
2 #define _TABLE_MARSHAL_TYPES_H_
3 typedef UINT16 marshalIndex_t;
A structure contains a list of elements to unmarshal. Each of the entries is a UINT16. The structure
descriptor is: The values array contains indicators for the things to marshal. The elements parameter
indicates how many different entities are unmarshaled. This number nominally corresponds to the number
of rows in the Part 2 table that describes the structure (the number of rows minus the title row and any
error code rows). A schematic of a simple structure entry is shown here but the values are not actually in
a structure. As shown, the third value is the offset in the structure where the value is placed when
unmarshaled, or fetched from when marshaling. This is sufficient when the element type indicated by
index is always a simple type and never a union or array.This is just shown for illustrative purposes.
386 } TPMI_ALG_CIPHER_MODE_mst;
387 typedef const struct TPMS_EMPTY_mst
388 {
389 UINT8 marshalType;
390 UINT8 elements;
391 UINT16 values[3];
392 } TPMS_EMPTY_mst;
393 typedef const struct TPMS_ALGORITHM_DESCRIPTION_mst
394 {
395 UINT8 marshalType;
396 UINT8 elements;
397 UINT16 values[6];
398 } TPMS_ALGORITHM_DESCRIPTION_mst;
399 typedef struct TPMU_HA_mst
400 {
401 BYTE countOfselectors;
402 BYTE modifiers;
403 UINT16 offsetOfUnmarshalTypes;
404 UINT32 selectors[9];
405 UINT16 marshalingTypes[9];
406 } TPMU_HA_mst;
407 typedef const struct TPMT_HA_mst
408 {
409 UINT8 marshalType;
410 UINT8 elements;
411 UINT16 values[6];
412 } TPMT_HA_mst;
413 typedef const struct TPMS_PCR_SELECT_mst
414 {
415 UINT8 marshalType;
416 UINT8 elements;
417 UINT16 values[6];
418 } TPMS_PCR_SELECT_mst;
419 typedef const struct TPMS_PCR_SELECTION_mst
420 {
421 UINT8 marshalType;
422 UINT8 elements;
423 UINT16 values[9];
424 } TPMS_PCR_SELECTION_mst;
425 typedef const struct TPMT_TK_CREATION_mst
426 {
427 UINT8 marshalType;
428 UINT8 elements;
429 UINT16 values[9];
430 } TPMT_TK_CREATION_mst;
431 typedef const struct TPMT_TK_VERIFIED_mst
432 {
433 UINT8 marshalType;
434 UINT8 elements;
435 UINT16 values[9];
436 } TPMT_TK_VERIFIED_mst;
437 typedef const struct TPMT_TK_AUTH_mst
438 {
439 UINT8 marshalType;
440 UINT8 elements;
441 UINT16 values[9];
442 } TPMT_TK_AUTH_mst;
443 typedef const struct TPMT_TK_HASHCHECK_mst
444 {
445 UINT8 marshalType;
446 UINT8 elements;
447 UINT16 values[9];
448 } TPMT_TK_HASHCHECK_mst;
449 typedef const struct TPMS_ALG_PROPERTY_mst
450 {
451 UINT8 marshalType;
518 {
519 UINT8 marshalType;
520 UINT8 elements;
521 UINT16 values[6];
522 } TPMS_QUOTE_INFO_mst;
523 typedef const struct TPMS_COMMAND_AUDIT_INFO_mst
524 {
525 UINT8 marshalType;
526 UINT8 elements;
527 UINT16 values[12];
528 } TPMS_COMMAND_AUDIT_INFO_mst;
529 typedef const struct TPMS_SESSION_AUDIT_INFO_mst
530 {
531 UINT8 marshalType;
532 UINT8 elements;
533 UINT16 values[6];
534 } TPMS_SESSION_AUDIT_INFO_mst;
535 typedef const struct TPMS_CREATION_INFO_mst
536 {
537 UINT8 marshalType;
538 UINT8 elements;
539 UINT16 values[6];
540 } TPMS_CREATION_INFO_mst;
541 typedef const struct TPMS_NV_CERTIFY_INFO_mst
542 {
543 UINT8 marshalType;
544 UINT8 elements;
545 UINT16 values[9];
546 } TPMS_NV_CERTIFY_INFO_mst;
547 typedef const struct TPMS_NV_DIGEST_CERTIFY_INFO_mst
548 {
549 UINT8 marshalType;
550 UINT8 elements;
551 UINT16 values[6];
552 } TPMS_NV_DIGEST_CERTIFY_INFO_mst;
553 typedef const struct TPMI_ST_ATTEST_mst {
554 UINT8 marshalType;
555 UINT8 modifiers;
556 UINT8 errorCode;
557 UINT8 ranges;
558 UINT8 singles;
559 UINT32 values[3];
560 } TPMI_ST_ATTEST_mst;
561 typedef struct TPMU_ATTEST_mst
562 {
563 BYTE countOfselectors;
564 BYTE modifiers;
565 UINT16 offsetOfUnmarshalTypes;
566 UINT32 selectors[8];
567 UINT16 marshalingTypes[8];
568 } TPMU_ATTEST_mst;
569 typedef const struct TPMS_ATTEST_mst
570 {
571 UINT8 marshalType;
572 UINT8 elements;
573 UINT16 values[21];
574 } TPMS_ATTEST_mst;
575 typedef const struct TPMS_AUTH_COMMAND_mst
576 {
577 UINT8 marshalType;
578 UINT8 elements;
579 UINT16 values[12];
580 } TPMS_AUTH_COMMAND_mst;
581 typedef const struct TPMS_AUTH_RESPONSE_mst
582 {
583 UINT8 marshalType;
650 {
651 UINT8 marshalType;
652 UINT8 elements;
653 UINT16 values[6];
654 } TPMS_DERIVE_mst;
655 typedef const struct TPMS_SENSITIVE_CREATE_mst
656 {
657 UINT8 marshalType;
658 UINT8 elements;
659 UINT16 values[6];
660 } TPMS_SENSITIVE_CREATE_mst;
661 typedef const struct TPMS_SCHEME_HASH_mst
662 {
663 UINT8 marshalType;
664 UINT8 elements;
665 UINT16 values[3];
666 } TPMS_SCHEME_HASH_mst;
667 typedef const struct TPMS_SCHEME_ECDAA_mst
668 {
669 UINT8 marshalType;
670 UINT8 elements;
671 UINT16 values[6];
672 } TPMS_SCHEME_ECDAA_mst;
673 typedef const struct TPMI_ALG_KEYEDHASH_SCHEME_mst {
674 UINT8 marshalType;
675 UINT8 modifiers;
676 UINT8 errorCode;
677 UINT32 values[4];
678 } TPMI_ALG_KEYEDHASH_SCHEME_mst;
679 typedef const struct TPMS_SCHEME_XOR_mst
680 {
681 UINT8 marshalType;
682 UINT8 elements;
683 UINT16 values[6];
684 } TPMS_SCHEME_XOR_mst;
685 typedef struct TPMU_SCHEME_KEYEDHASH_mst
686 {
687 BYTE countOfselectors;
688 BYTE modifiers;
689 UINT16 offsetOfUnmarshalTypes;
690 UINT32 selectors[3];
691 UINT16 marshalingTypes[3];
692 } TPMU_SCHEME_KEYEDHASH_mst;
693 typedef const struct TPMT_KEYEDHASH_SCHEME_mst
694 {
695 UINT8 marshalType;
696 UINT8 elements;
697 UINT16 values[6];
698 } TPMT_KEYEDHASH_SCHEME_mst;
699 typedef struct TPMU_SIG_SCHEME_mst
700 {
701 BYTE countOfselectors;
702 BYTE modifiers;
703 UINT16 offsetOfUnmarshalTypes;
704 UINT32 selectors[8];
705 UINT16 marshalingTypes[8];
706 } TPMU_SIG_SCHEME_mst;
707 typedef const struct TPMT_SIG_SCHEME_mst
708 {
709 UINT8 marshalType;
710 UINT8 elements;
711 UINT16 values[6];
712 } TPMT_SIG_SCHEME_mst;
713 typedef struct TPMU_KDF_SCHEME_mst
714 {
715 BYTE countOfselectors;
This structure combines all the individual marshaling structures to build something that can be referenced
by offset rather than full address
9.10.8.1 TableDrivenMarshal.c
1 #include <assert.h>
2 #include "Tpm.h"
3 #include "Marshal.h"
4 #include "TableMarshal.h"
5 #if TABLE_DRIVEN_MARSHAL
6 extern ArrayMarshal_mst ArrayLookupTable[];
7
8 extern UINT16 MarshalLookupTable[];
9
10 typedef struct { int a; } External_Structure_t;
11
12 extern struct Exernal_Structure_t MarshalData;
13
14 #define IS_SUCCESS(UNMARSHAL_FUNCTION) \
15 (TPM_RC_SUCCESS == (result = (UNMARSHAL_FUNCTION)))
16 marshalIndex_t IntegerDispatch[] = {
17 UINT8_MARSHAL_REF, UINT16_MARSHAL_REF, UINT32_MARSHAL_REF, UINT64_MARSHAL_REF,
18 INT8_MARSHAL_REF, INT16_MARSHAL_REF, INT32_MARSHAL_REF, INT64_MARSHAL_REF
19 };
20
21 #if 1
22 #define GetDescriptor(reference) \
23 ((MarshalHeader_mst *)(((BYTE *)(&MarshalData)) + (reference & NULL_MASK)))
24 #else
25 static const MarshalHeader_mst *GetDescriptor(marshalIndex_t index)
26 {
27 const MarshalHeader_mst *mst = MarshalLookupTable[index & NULL_MASK];
28 return mst;
29 }
30 #endif
31 #define GetUnionDescriptor(_index_) \
32 ((UnionMarshal_mst *)GetDescriptor(_index_))
33 #define GetArrayDescriptor(_index_) \
34 ((ArrayMarshal_mst *))ArrayLookupTable[_index_ & NULL_MASK])
35
36 //*** GetUnmarshaledInteger()
37 // Gets the unmarshaled value and normalizes it to a UIN32 for other
38 // processing (comparisons and such).
39 static UINT32 GetUnmarshaledInteger(
40 marshalIndex_t type,
41 const void *target
42 )
43 {
44 int size = (type & SIZE_MASK);
45 //
46 if(size == FOUR_BYTES)
47 return *((UINT32 *)target);
48 if(type & IS_SIGNED)
49 {
50 if(size == TWO_BYTES)
51 return (UINT32)*((int16_t *)target);
52 return (UINT32)*((int8_t *)target);
53 }
54 if(size == TWO_BYTES)
55 return (UINT32)*((UINT16 *)target);
56 return (UINT32)*((UINT8 *)target);
57 }
58 static UINT32 GetSelector(
59 void *structure,
60 const UINT16 *values,
61 UINT16 descriptor
62 )
63 {
64 uint sel = GET_ELEMENT_NUMBER(descriptor);
65 // Get the offset of the value in the unmarshaled structure
66 const UINT16 *entry = &values[(sel * 3)];
67 //
68 return GetUnmarshaledInteger(GET_ELEMENT_SIZE(entry[0]),
69 ((UINT8 *)structure) + entry[2]);
70 }
71 static TPM_RC UnmarshalBytes(
72 UINT8 *target, // IN/OUT: place to put the bytes
73 UINT8 **buffer, // IN/OUT: source of the input data
74 INT32 *size, // IN/OUT: remaining bytes in the input buffer
75 int count // IN: number of bytes to get
76 )
77 {
78 if((*size -= count) >= 0)
79 {
80 memcpy(target, *buffer, count);
81 *buffer += count;
82 return TPM_RC_SUCCESS;
83 }
84 return TPM_RC_INSUFFICIENT;
85 }
9.10.8.1.1.1 MarshalBytes()
9.10.8.1.1.2 ArrayUnmarshal()
9.10.8.1.1.3 ArrayMarshal()
9.10.8.1.1.4 UnmarshalUnion()
148 TPM_RC
149 UnmarshalUnion(
150 UINT16 typeIndex, // IN: the thing to unmarshal
151 void *target, // IN: were the data goes to
152 UINT8 **buffer, // IN/OUT: the data source buffer
153 INT32 *size, // IN/OUT: the remaining size
154 UINT32 selector
155 )
156 {
157 int i;
158 UnionMarshal_mst *ut = GetUnionDescriptor(typeIndex);
159 marshalIndex_t selected;
160 //
161 for(i = 0; i < ut->countOfselectors; i++)
162 {
163 if(selector == ut->selectors[i])
164 {
165 UINT8 *offset = ((UINT8 *)ut) + ut->offsetOfUnmarshalTypes;
166 // Get the selected thing to unmarshal
167 selected = ((marshalIndex_t *)offset)[i];
168 if(ut->modifiers & IS_ARRAY_UNION)
169 return UnmarshalBytes(target, buffer, size, selected);
170 else
171 {
172 // Propagate NULL_FLAG if the null flag was
173 // propagated to the structure containing the union
174 selected |= (typeIndex & NULL_FLAG);
175 return Unmarshal(selected, target, buffer, size);
176 }
177 }
178 }
179 // Didn't find the value.
180 return TPM_RC_SELECTOR;
181 }
9.10.8.1.1.5 MarshalUnion()
182 UINT16
183 MarshalUnion(
184 UINT16 typeIndex, // IN: the thing to marshal
185 void *source, // IN: were the data comes from
186 UINT8 **buffer, // IN/OUT: the data source buffer
187 INT32 *size, // IN/OUT: the remaining size
188 UINT32 selector // IN: the union selector
189 )
190 {
191 int i;
192 UnionMarshal_mst *ut = GetUnionDescriptor(typeIndex);
193 marshalIndex_t selected;
194 //
195 for(i = 0; i < ut->countOfselectors; i++)
196 {
197 if(selector == ut->selectors[i])
198 {
199 UINT8 *offset = ((UINT8 *)ut) + ut->offsetOfUnmarshalTypes;
200 // Get the selected thing to unmarshal
201 selected = ((marshalIndex_t *)offset)[i];
202 if(ut->modifiers & IS_ARRAY_UNION)
203 return MarshalBytes(source, buffer, size, selected);
204 else
205 return Marshal(selected, source, buffer, size);
206 }
207 }
208 if(size != NULL)
209 *size = -1;
210 return 0;
211 }
212 TPM_RC
213 UnmarshalInteger(
214 int iSize, // IN: Number of bytes in the integer
215 void *target, // OUT: receives the integer
216 UINT8 **buffer, // IN/OUT: source of the data
217 INT32 *size, // IN/OUT: amount of data available
218 UINT32 *value // OUT: optional copy of 'target'
219 )
220 {
221 // This is just to save typing
222 #define _MB_ (*buffer)
223 // The size is a power of two so convert to regular integer
224 int bytes = (1 << (iSize & SIZE_MASK));
225 //
226 // Check to see if there is enough data to fulfill the request
227 if((*size -= bytes) >= 0)
228 {
229 // The most comon size
230 if(bytes == 4)
231 {
232 *((UINT32 *)target) = (UINT32)((((((_MB_[0] << 8) | _MB_[1]) << 8)
233 | _MB_[2]) << 8) | _MB_[3]);
234 // If a copy is needed, copy it.
235 if(value != NULL)
236 *value = *((UINT32 *)target);
237 }
238 else if(bytes == 2)
239 {
240 *((UINT16 *)target) = (UINT16)((_MB_[0] << 8) | _MB_[1]);
241 // If a copy is needed, copy with the appropriate sign extension
242 if(value != NULL)
243 {
244 if(iSize & IS_SIGNED)
9.10.8.1.1.6 Unmarshal()
This is the function that performs unmarshaling of different numbered types. Each TPM type has a
number. The number is used to lookup the address of the data structure that describes how to unmarshal
that data type.
274 TPM_RC
275 Unmarshal(
276 UINT16 typeIndex, // IN: the thing to marshal
277 void *target, // IN: were the data goes from
278 UINT8 **buffer, // IN/OUT: the data source buffer
279 INT32 *size // IN/OUT: the remaining size
280 )
281 {
282 const MarshalHeader_mst *sel;
283 TPM_RC result;
284 //
285 #define _target ((UINT8 *)target)
286 sel = GetDescriptor(typeIndex);
287 switch(sel->marshalType)
288 {
289 case UINT_MTYPE:
290 {
291 // A simple signed or unsigned integer value.
292 return UnmarshalInteger(sel->modifiers, target,
293 buffer, size, NULL);
294 }
295 case VALUES_MTYPE:
296 {
297 // This is the general-purpose structure that can handle things like
298 // TPMI_DH_PARENT that has multiple ranges, multiple singles and a
299 // 'null' value. When things cover a large range with holes in the range
300 // they can be turned into multiple ranges. There is no option for a bit
301 // field.
302 // The structure is:
303 // typedef const struct ValuesMarshal_mst
304 // {
305 // UINT8 marshalType; // VALUES_MTYPE
306 // UINT8 modifiers;
307 // UINT8 errorCode;
308 // UINT8 ranges;
309 // UINT8 singles;
310 // UINT32 values[1];
311 // } ValuesMarshal_mst;
312 // Unmarshal the base type
313 UINT32 val;
314 if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
315 buffer, size, &val)))
316 {
317 ValuesMarshal_mst *vmt = ((ValuesMarshal_mst *)sel);
318 const UINT32 *check = vmt->values;
319 //
320 // if the TAKES_NULL flag is set, then the first entry in the values
321 // list is the NULL value. Iy is not included in the 'ranges' or
322 // 'singles' count.
323 if((vmt->modifiers & TAKES_NULL) && (val == *check++))
324 {
325 if((typeIndex & NULL_FLAG) == 0)
326 result = (TPM_RC)(sel->errorCode);
327 }
328 // No NULL value or input is not the NULL value
329 else
330 {
331 int i;
332 //
333 // Check all the min-max ranges.
334 for(i = vmt->ranges - 1; i >= 0; check = &check[2], i--)
335 if((UINT32)(val - check[0]) <= check[1])
336 break;
337 // if the input is in a selected range, then i >= 0
338 if(i < 0)
339 {
340 // Not in any range, so check sigles
341 for(i = vmt->singles - 1; i >= 0; i--)
342 if(val == check[i])
343 break;
344 }
345 // If input not in range and not in any single so return error
346 if(i < 0)
347 result = (TPM_RC)(sel->errorCode);
348 }
349 }
350 break;
351 }
352 case TABLE_MTYPE:
353 {
354 // This is a table with or without bit checking. The input is checked
355 // against each value in the table. If the value is in the table, and
356 // a bits table is present, then the bit field is checked to see if the
357 // indiated value is implemented. For example, if there is a table of
358 // allowed RSA key sises and the 2nd entry matches, then the 2nd bit in
359 // thed bit field is check to see if that allowwed size is implemented in
360 // this TPM.
361 // typedef const struct TableMarshal_mst
362 // {
363 // UINT8 marshalType; // TABLE_MTYPE
364 // UINT8 modifiers;
365 // UINT8 errorCode;
366 // UINT8 singles;
367 // UINT32 values[1];
368 // } TableMarshal_mst;
369
370 UINT32 val;
371 //
372 // Unmarshal the base type
373 if(IS_SUCCESS(UnmarshalInteger(sel->modifiers, target,
374 buffer, size, &val)))
375 {
376 TableMarshal_mst *tmt = ((TableMarshal_mst *)sel);
377 const UINT32 *check = tmt->values;
378 //
379 // If this type has a null value, then it is the first value in the
380 // list of values. It does not count in the count of values
381 if((tmt->modifiers & TAKES_NULL) && (val == *check++))
382 {
383 if((typeIndex & NULL_FLAG) == 0)
384 result = (TPM_RC)(sel->errorCode);
385 }
386 else
387 {
388 int i;
389 //
390 // Process the singles
391 for(i = tmt->singles - 1; i >= 0; i--)
392 {
393 // does the input value match the value in the table
394 if(val == check[i])
395 {
396 // If there is an associated bit table, make sure that the
corresponding
9.10.8.1.1.7 Marshal()
This is the function that drives marshaling of output. Because there is no validation of the output, there is
a lot less code.
9.10.8.2 TableMarshalData.c
This file contains the data initializer used for the table-driven marshaling code.
1 #include "Tpm.h"
2 #if TABLE_DRIVEN_MARSHAL
3 #include "TableMarshal.h"
4 #include "Marshal.h"
5 ArrayMarshal_mst ArrayLookupTable[] = {
6 ARRAY_MARSHAL_ENTRY(UINT8),
7 ARRAY_MARSHAL_ENTRY(TPM_CC),
8 ARRAY_MARSHAL_ENTRY(TPMA_CC),
9 ARRAY_MARSHAL_ENTRY(TPM_ALG_ID),
10 ARRAY_MARSHAL_ENTRY(TPM_HANDLE),
11 ARRAY_MARSHAL_ENTRY(TPM2B_DIGEST),
12 ARRAY_MARSHAL_ENTRY(TPMT_HA),
13 ARRAY_MARSHAL_ENTRY(TPMS_PCR_SELECTION),
14 ARRAY_MARSHAL_ENTRY(TPMS_ALG_PROPERTY),
15 ARRAY_MARSHAL_ENTRY(TPMS_TAGGED_PROPERTY),
16 ARRAY_MARSHAL_ENTRY(TPMS_TAGGED_PCR_SELECT),
17 ARRAY_MARSHAL_ENTRY(TPM_ECC_CURVE),
18 ARRAY_MARSHAL_ENTRY(TPMS_TAGGED_POLICY),
19 ARRAY_MARSHAL_ENTRY(TPMS_ACT_DATA),
20 ARRAY_MARSHAL_ENTRY(TPMS_AC_OUTPUT)};
21 MarshalData_st MarshalData = {
22 // UINT8_DATA
23 {UINT_MTYPE, 0},
24 // UINT16_DATA
25 {UINT_MTYPE, 1},
26 // UINT32_DATA
27 {UINT_MTYPE, 2},
28 // UINT64_DATA
29 {UINT_MTYPE, 3},
30 // INT8_DATA
31 {UINT_MTYPE, 0 + IS_SIGNED},
32 // INT16_DATA
33 {UINT_MTYPE, 1 + IS_SIGNED},
34 // INT32_DATA
35 {UINT_MTYPE, 2 + IS_SIGNED},
36 // INT64_DATA
37 {UINT_MTYPE, 3 + IS_SIGNED},
38 // UINT0_DATA
39 {NULL_MTYPE, 0},
40 // TPM_ECC_CURVE_DATA
41 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_CURVE,
42 {TPM_ECC_NONE,
43 RANGE(1, 32, UINT16),
44 ((ECC_NIST_P192 << 0) | (ECC_NIST_P224 << 1) | (ECC_NIST_P256 << 2) |
45 (ECC_NIST_P384 << 3) | (ECC_NIST_P521 << 4) | (ECC_BN_P256 << 15) |
46 (ECC_BN_P638 << 16) | (ECC_SM2_P256 << 31))}},
47 // TPM_CLOCK_ADJUST_DATA
48 {MIN_MAX_MTYPE, ONE_BYTES|IS_SIGNED, (UINT8)TPM_RC_VALUE,
49 {RANGE(TPM_CLOCK_COARSE_SLOWER, TPM_CLOCK_COARSE_FASTER, INT8)}},
50 // TPM_EO_DATA
51 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE,
52 {RANGE(TPM_EO_EQ, TPM_EO_BITCLEAR, UINT16)}},
53 // TPM_SU_DATA
54 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 2,
55 {TPM_SU_CLEAR, TPM_SU_STATE}},
56 // TPM_SE_DATA
57 {TABLE_MTYPE, ONE_BYTES, (UINT8)TPM_RC_VALUE, 3,
58 {TPM_SE_HMAC, TPM_SE_POLICY, TPM_SE_TRIAL}},
59 // TPM_CAP_DATA
60 {VALUES_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 1, 1,
61 {RANGE(TPM_CAP_ALGS, TPM_CAP_ACT, UINT32),
62 TPM_CAP_VENDOR_PROPERTY}},
63 // TPMA_ALGORITHM_DATA
64 {ATTRIBUTES_MTYPE, FOUR_BYTES, 0xFFFFF8F0},
65 // TPMA_OBJECT_DATA
66 {ATTRIBUTES_MTYPE, FOUR_BYTES, 0xFFF0F309},
67 // TPMA_SESSION_DATA
68 {ATTRIBUTES_MTYPE, ONE_BYTES, 0x00000018},
69 // TPMA_ACT_DATA
70 {ATTRIBUTES_MTYPE, FOUR_BYTES, 0xFFFFFFFC},
71 // TPMI_YES_NO_DATA
72 {TABLE_MTYPE, ONE_BYTES, (UINT8)TPM_RC_VALUE, 2,
73 {NO, YES}},
74 // TPMI_DH_OBJECT_DATA
75 {VALUES_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 2, 0,
76 {TPM_RH_NULL,
77 RANGE(TRANSIENT_FIRST, TRANSIENT_LAST, UINT32),
78 RANGE(PERSISTENT_FIRST, PERSISTENT_LAST, UINT32)}},
79 // TPMI_DH_PARENT_DATA
80 {VALUES_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 2, 3,
81 {TPM_RH_NULL,
82 RANGE(TRANSIENT_FIRST, TRANSIENT_LAST, UINT32),
83 RANGE(PERSISTENT_FIRST, PERSISTENT_LAST, UINT32),
84 TPM_RH_OWNER, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM}},
85 // TPMI_DH_PERSISTENT_DATA
86 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
87 {RANGE(PERSISTENT_FIRST, PERSISTENT_LAST, UINT32)}},
88 // TPMI_DH_ENTITY_DATA
89 {VALUES_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 5, 4,
90 {TPM_RH_NULL,
91 RANGE(TRANSIENT_FIRST, TRANSIENT_LAST, UINT32),
92 RANGE(PERSISTENT_FIRST, PERSISTENT_LAST, UINT32),
93 RANGE(NV_INDEX_FIRST, NV_INDEX_LAST, UINT32),
94 RANGE(PCR_FIRST, PCR_LAST, UINT32),
95 RANGE(TPM_RH_AUTH_00, TPM_RH_AUTH_FF, UINT32),
96 TPM_RH_OWNER, TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM}},
97 // TPMI_DH_PCR_DATA
98 {MIN_MAX_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE,
99 {TPM_RH_NULL,
100 RANGE(PCR_FIRST, PCR_LAST, UINT32)}},
101 // TPMI_SH_AUTH_SESSION_DATA
102 {VALUES_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 2, 0,
103 {TPM_RS_PW,
104 RANGE(HMAC_SESSION_FIRST, HMAC_SESSION_LAST, UINT32),
105 RANGE(POLICY_SESSION_FIRST, POLICY_SESSION_LAST, UINT32)}},
106 // TPMI_SH_HMAC_DATA
107 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
108 {RANGE(HMAC_SESSION_FIRST, HMAC_SESSION_LAST, UINT32)}},
109 // TPMI_SH_POLICY_DATA
110 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
111 {RANGE(POLICY_SESSION_FIRST, POLICY_SESSION_LAST, UINT32)}},
112 // TPMI_DH_CONTEXT_DATA
113 {VALUES_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 3, 0,
114 {RANGE(HMAC_SESSION_FIRST, HMAC_SESSION_LAST, UINT32),
115 RANGE(POLICY_SESSION_FIRST, POLICY_SESSION_LAST, UINT32),
116 RANGE(TRANSIENT_FIRST, TRANSIENT_LAST, UINT32)}},
117 // TPMI_DH_SAVED_DATA
118 {VALUES_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 2, 3,
119 {RANGE(HMAC_SESSION_FIRST, HMAC_SESSION_LAST, UINT32),
120 RANGE(POLICY_SESSION_FIRST, POLICY_SESSION_LAST, UINT32),
121 0x80000000, 0x80000001, 0x80000002}},
122 // TPMI_RH_HIERARCHY_DATA
123 {TABLE_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 3,
124 {TPM_RH_NULL,
125 TPM_RH_OWNER, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM}},
126 // TPMI_RH_ENABLES_DATA
127 {TABLE_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 4,
128 {TPM_RH_NULL,
129 TPM_RH_OWNER, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM, TPM_RH_PLATFORM_NV}},
130 // TPMI_RH_HIERARCHY_AUTH_DATA
131 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 4,
132 {TPM_RH_OWNER, TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM}},
133 // TPMI_RH_HIERARCHY_POLICY_DATA
134 {VALUES_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 1, 4,
135 {RANGE(TPM_RH_ACT_0, TPM_RH_ACT_F, UINT32),
136 TPM_RH_OWNER, TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_PLATFORM}},
137 // TPMI_RH_PLATFORM_DATA
138 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 1,
139 {TPM_RH_PLATFORM}},
140 // TPMI_RH_OWNER_DATA
141 {TABLE_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 1,
142 {TPM_RH_NULL,
143 TPM_RH_OWNER}},
144 // TPMI_RH_ENDORSEMENT_DATA
145 {TABLE_MTYPE, FOUR_BYTES|TAKES_NULL, (UINT8)TPM_RC_VALUE, 1,
146 {TPM_RH_NULL,
147 TPM_RH_ENDORSEMENT}},
148 // TPMI_RH_PROVISION_DATA
149 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 2,
150 {TPM_RH_OWNER, TPM_RH_PLATFORM}},
151 // TPMI_RH_CLEAR_DATA
152 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 2,
153 {TPM_RH_LOCKOUT, TPM_RH_PLATFORM}},
154 // TPMI_RH_NV_AUTH_DATA
155 {VALUES_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 1, 2,
156 {RANGE(NV_INDEX_FIRST, NV_INDEX_LAST, UINT32),
157 TPM_RH_OWNER, TPM_RH_PLATFORM}},
158 // TPMI_RH_LOCKOUT_DATA
159 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 1,
160 {TPM_RH_LOCKOUT}},
161 // TPMI_RH_NV_INDEX_DATA
162 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
163 {RANGE(NV_INDEX_FIRST, NV_INDEX_LAST, UINT32)}},
164 // TPMI_RH_AC_DATA
165 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
166 {RANGE(AC_FIRST, AC_LAST, UINT32)}},
167 // TPMI_RH_ACT_DATA
168 {MIN_MAX_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE,
169 {RANGE(TPM_RH_ACT_0, TPM_RH_ACT_F, UINT32)}},
170 // TPMI_ALG_HASH_DATA
171 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_HASH,
172 {TPM_ALG_NULL,
173 RANGE(4, 41, UINT16),
174 ((ALG_SHA1 << 0) | (ALG_SHA256 << 7) | (ALG_SHA384 << 8) |
175 (ALG_SHA512 << 9) | (ALG_SM3_256 << 14)),
176 ((ALG_SHA3_256 << 3)|(ALG_SHA3_384 << 4)|(ALG_SHA3_512 << 5))}},
177 // TPMI_ALG_ASYM_DATA
178 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_ASYMMETRIC,
179 {TPM_ALG_NULL,
180 RANGE(1, 35, UINT16),
181 ((ALG_RSA << 0)),
182 ((ALG_ECC << 2))}},
183 // TPMI_ALG_SYM_DATA
184 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_SYMMETRIC,
185 {TPM_ALG_NULL,
186 RANGE(3, 38, UINT16),
187 ((ALG_TDES << 0)|(ALG_AES << 3)|(ALG_XOR << 7)|(ALG_SM4 << 16)),
188 ((ALG_CAMELLIA << 3))}},
189 // TPMI_ALG_SYM_OBJECT_DATA
190 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_SYMMETRIC,
191 {TPM_ALG_NULL,
192 RANGE(3, 38, UINT16),
193 ((ALG_TDES << 0)|(ALG_AES << 3)|(ALG_SM4 << 16)),
194 ((ALG_CAMELLIA << 3))}},
195 // TPMI_ALG_SYM_MODE_DATA
196 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_MODE,
197 {TPM_ALG_NULL,
198 RANGE(63, 68, UINT16),
331 SET_ELEMENT_TYPE(SIMPLE_STYPE),
332 TPM2B_DIGEST_MARSHAL_REF,
333 (UINT16)(offsetof(TPMT_TK_AUTH, digest))}},
334 // TPMT_TK_HASHCHECK_DATA
335 {STRUCTURE_MTYPE, 3, {
336 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
337 Type13_MARSHAL_REF,
338 (UINT16)(offsetof(TPMT_TK_HASHCHECK, tag)),
339 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
340 TPMI_RH_HIERARCHY_MARSHAL_REF|NULL_FLAG,
341 (UINT16)(offsetof(TPMT_TK_HASHCHECK, hierarchy)),
342 SET_ELEMENT_TYPE(SIMPLE_STYPE),
343 TPM2B_DIGEST_MARSHAL_REF,
344 (UINT16)(offsetof(TPMT_TK_HASHCHECK, digest))}},
345 // TPMS_ALG_PROPERTY_DATA
346 {STRUCTURE_MTYPE, 2, {
347 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
348 TPM_ALG_ID_MARSHAL_REF,
349 (UINT16)(offsetof(TPMS_ALG_PROPERTY, alg)),
350 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
351 TPMA_ALGORITHM_MARSHAL_REF,
352 (UINT16)(offsetof(TPMS_ALG_PROPERTY, algProperties))}},
353 // TPMS_TAGGED_PROPERTY_DATA
354 {STRUCTURE_MTYPE, 2, {
355 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
356 TPM_PT_MARSHAL_REF,
357 (UINT16)(offsetof(TPMS_TAGGED_PROPERTY, property)),
358 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
359 UINT32_MARSHAL_REF,
360 (UINT16)(offsetof(TPMS_TAGGED_PROPERTY, value))}},
361 // TPMS_TAGGED_PCR_SELECT_DATA
362 {STRUCTURE_MTYPE, 3, {
363 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
364 TPM_PT_PCR_MARSHAL_REF,
365 (UINT16)(offsetof(TPMS_TAGGED_PCR_SELECT, tag)),
366 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(ONE_BYTES),
367 Type08_MARSHAL_REF,
368 (UINT16)(offsetof(TPMS_TAGGED_PCR_SELECT, sizeofSelect)),
369 SET_ELEMENT_TYPE(ARRAY_STYPE)|SET_ELEMENT_NUMBER(1),
370 UINT8_ARRAY_MARSHAL_INDEX,
371 (UINT16)(offsetof(TPMS_TAGGED_PCR_SELECT, pcrSelect))}},
372 // TPMS_TAGGED_POLICY_DATA
373 {STRUCTURE_MTYPE, 2, {
374 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
375 TPM_HANDLE_MARSHAL_REF,
376 (UINT16)(offsetof(TPMS_TAGGED_POLICY, handle)),
377 SET_ELEMENT_TYPE(SIMPLE_STYPE),
378 TPMT_HA_MARSHAL_REF,
379 (UINT16)(offsetof(TPMS_TAGGED_POLICY, policyHash))}},
380 // TPMS_ACT_DATA_DATA
381 {STRUCTURE_MTYPE, 3, {
382 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
383 TPM_HANDLE_MARSHAL_REF,
384 (UINT16)(offsetof(TPMS_ACT_DATA, handle)),
385 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
386 UINT32_MARSHAL_REF,
387 (UINT16)(offsetof(TPMS_ACT_DATA, timeout)),
388 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
389 TPMA_ACT_MARSHAL_REF,
390 (UINT16)(offsetof(TPMS_ACT_DATA, attributes))}},
391 // TPML_CC_DATA
392 {LIST_MTYPE,
393 (UINT8)(offsetof(TPML_CC, commandCodes)),
394 Type15_MARSHAL_REF,
395 TPM_CC_ARRAY_MARSHAL_INDEX},
396 // TPML_CCA_DATA
397 {LIST_MTYPE,
398 (UINT8)(offsetof(TPML_CCA, commandAttributes)),
399 Type15_MARSHAL_REF,
400 TPMA_CC_ARRAY_MARSHAL_INDEX},
401 // TPML_ALG_DATA
402 {LIST_MTYPE,
403 (UINT8)(offsetof(TPML_ALG, algorithms)),
404 Type17_MARSHAL_REF,
405 TPM_ALG_ID_ARRAY_MARSHAL_INDEX},
406 // TPML_HANDLE_DATA
407 {LIST_MTYPE,
408 (UINT8)(offsetof(TPML_HANDLE, handle)),
409 Type18_MARSHAL_REF,
410 TPM_HANDLE_ARRAY_MARSHAL_INDEX},
411 // TPML_DIGEST_DATA
412 {LIST_MTYPE,
413 (UINT8)(offsetof(TPML_DIGEST, digests)),
414 Type19_MARSHAL_REF,
415 TPM2B_DIGEST_ARRAY_MARSHAL_INDEX},
416 // TPML_DIGEST_VALUES_DATA
417 {LIST_MTYPE,
418 (UINT8)(offsetof(TPML_DIGEST_VALUES, digests)),
419 Type20_MARSHAL_REF,
420 TPMT_HA_ARRAY_MARSHAL_INDEX},
421 // TPML_PCR_SELECTION_DATA
422 {LIST_MTYPE,
423 (UINT8)(offsetof(TPML_PCR_SELECTION, pcrSelections)),
424 Type20_MARSHAL_REF,
425 TPMS_PCR_SELECTION_ARRAY_MARSHAL_INDEX},
426 // TPML_ALG_PROPERTY_DATA
427 {LIST_MTYPE,
428 (UINT8)(offsetof(TPML_ALG_PROPERTY, algProperties)),
429 Type22_MARSHAL_REF,
430 TPMS_ALG_PROPERTY_ARRAY_MARSHAL_INDEX},
431 // TPML_TAGGED_TPM_PROPERTY_DATA
432 {LIST_MTYPE,
433 (UINT8)(offsetof(TPML_TAGGED_TPM_PROPERTY, tpmProperty)),
434 Type23_MARSHAL_REF,
435 TPMS_TAGGED_PROPERTY_ARRAY_MARSHAL_INDEX},
436 // TPML_TAGGED_PCR_PROPERTY_DATA
437 {LIST_MTYPE,
438 (UINT8)(offsetof(TPML_TAGGED_PCR_PROPERTY, pcrProperty)),
439 Type24_MARSHAL_REF,
440 TPMS_TAGGED_PCR_SELECT_ARRAY_MARSHAL_INDEX},
441 // TPML_ECC_CURVE_DATA
442 {LIST_MTYPE,
443 (UINT8)(offsetof(TPML_ECC_CURVE, eccCurves)),
444 Type25_MARSHAL_REF,
445 TPM_ECC_CURVE_ARRAY_MARSHAL_INDEX},
446 // TPML_TAGGED_POLICY_DATA
447 {LIST_MTYPE,
448 (UINT8)(offsetof(TPML_TAGGED_POLICY, policies)),
449 Type26_MARSHAL_REF,
450 TPMS_TAGGED_POLICY_ARRAY_MARSHAL_INDEX},
451 // TPML_ACT_DATA_DATA
452 {LIST_MTYPE,
453 (UINT8)(offsetof(TPML_ACT_DATA, actData)),
454 Type27_MARSHAL_REF,
455 TPMS_ACT_DATA_ARRAY_MARSHAL_INDEX},
456 // TPMU_CAPABILITIES_DATA
457 {11, 0, (UINT16)(offsetof(TPMU_CAPABILITIES_mst, marshalingTypes)),
458 {(UINT32)TPM_CAP_ALGS, (UINT32)TPM_CAP_HANDLES,
459 (UINT32)TPM_CAP_COMMANDS, (UINT32)TPM_CAP_PP_COMMANDS,
460 (UINT32)TPM_CAP_AUDIT_COMMANDS, (UINT32)TPM_CAP_PCRS,
461 (UINT32)TPM_CAP_TPM_PROPERTIES, (UINT32)TPM_CAP_PCR_PROPERTIES,
462 (UINT32)TPM_CAP_ECC_CURVES, (UINT32)TPM_CAP_AUTH_POLICIES,
463 (UINT32)TPM_CAP_ACT},
464 {(UINT16)(TPML_ALG_PROPERTY_MARSHAL_REF),
465 (UINT16)(TPML_HANDLE_MARSHAL_REF),
466 (UINT16)(TPML_CCA_MARSHAL_REF),
467 (UINT16)(TPML_CC_MARSHAL_REF),
468 (UINT16)(TPML_CC_MARSHAL_REF),
469 (UINT16)(TPML_PCR_SELECTION_MARSHAL_REF),
470 (UINT16)(TPML_TAGGED_TPM_PROPERTY_MARSHAL_REF),
471 (UINT16)(TPML_TAGGED_PCR_PROPERTY_MARSHAL_REF),
472 (UINT16)(TPML_ECC_CURVE_MARSHAL_REF),
473 (UINT16)(TPML_TAGGED_POLICY_MARSHAL_REF),
474 (UINT16)(TPML_ACT_DATA_MARSHAL_REF)}
475 },
476 // TPMS_CAPABILITY_DATA_DATA
477 {STRUCTURE_MTYPE, 2, {
478 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
479 TPM_CAP_MARSHAL_REF,
480 (UINT16)(offsetof(TPMS_CAPABILITY_DATA, capability)),
481 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
482 TPMU_CAPABILITIES_MARSHAL_REF,
483 (UINT16)(offsetof(TPMS_CAPABILITY_DATA, data))}},
484 // TPMS_CLOCK_INFO_DATA
485 {STRUCTURE_MTYPE, 4, {
486 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(EIGHT_BYTES),
487 UINT64_MARSHAL_REF,
488 (UINT16)(offsetof(TPMS_CLOCK_INFO, clock)),
489 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
490 UINT32_MARSHAL_REF,
491 (UINT16)(offsetof(TPMS_CLOCK_INFO, resetCount)),
492 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
493 UINT32_MARSHAL_REF,
494 (UINT16)(offsetof(TPMS_CLOCK_INFO, restartCount)),
495 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(ONE_BYTES),
496 TPMI_YES_NO_MARSHAL_REF,
497 (UINT16)(offsetof(TPMS_CLOCK_INFO, safe))}},
498 // TPMS_TIME_INFO_DATA
499 {STRUCTURE_MTYPE, 2, {
500 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(EIGHT_BYTES),
501 UINT64_MARSHAL_REF,
502 (UINT16)(offsetof(TPMS_TIME_INFO, time)),
503 SET_ELEMENT_TYPE(SIMPLE_STYPE),
504 TPMS_CLOCK_INFO_MARSHAL_REF,
505 (UINT16)(offsetof(TPMS_TIME_INFO, clockInfo))}},
506 // TPMS_TIME_ATTEST_INFO_DATA
507 {STRUCTURE_MTYPE, 2, {
508 SET_ELEMENT_TYPE(SIMPLE_STYPE),
509 TPMS_TIME_INFO_MARSHAL_REF,
510 (UINT16)(offsetof(TPMS_TIME_ATTEST_INFO, time)),
511 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(EIGHT_BYTES),
512 UINT64_MARSHAL_REF,
513 (UINT16)(offsetof(TPMS_TIME_ATTEST_INFO, firmwareVersion))}},
514 // TPMS_CERTIFY_INFO_DATA
515 {STRUCTURE_MTYPE, 2, {
516 SET_ELEMENT_TYPE(SIMPLE_STYPE),
517 TPM2B_NAME_MARSHAL_REF,
518 (UINT16)(offsetof(TPMS_CERTIFY_INFO, name)),
519 SET_ELEMENT_TYPE(SIMPLE_STYPE),
520 TPM2B_NAME_MARSHAL_REF,
521 (UINT16)(offsetof(TPMS_CERTIFY_INFO, qualifiedName))}},
522 // TPMS_QUOTE_INFO_DATA
523 {STRUCTURE_MTYPE, 2, {
524 SET_ELEMENT_TYPE(SIMPLE_STYPE),
525 TPML_PCR_SELECTION_MARSHAL_REF,
526 (UINT16)(offsetof(TPMS_QUOTE_INFO, pcrSelect)),
527 SET_ELEMENT_TYPE(SIMPLE_STYPE),
528 TPM2B_DIGEST_MARSHAL_REF,
595 (UINT16)(TPMS_NV_CERTIFY_INFO_MARSHAL_REF),
596 (UINT16)(TPMS_NV_DIGEST_CERTIFY_INFO_MARSHAL_REF)}
597 },
598 // TPMS_ATTEST_DATA
599 {STRUCTURE_MTYPE, 7, {
600 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
601 TPM_GENERATED_MARSHAL_REF,
602 (UINT16)(offsetof(TPMS_ATTEST, magic)),
603 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
604 TPMI_ST_ATTEST_MARSHAL_REF,
605 (UINT16)(offsetof(TPMS_ATTEST, type)),
606 SET_ELEMENT_TYPE(SIMPLE_STYPE),
607 TPM2B_NAME_MARSHAL_REF,
608 (UINT16)(offsetof(TPMS_ATTEST, qualifiedSigner)),
609 SET_ELEMENT_TYPE(SIMPLE_STYPE),
610 TPM2B_DATA_MARSHAL_REF,
611 (UINT16)(offsetof(TPMS_ATTEST, extraData)),
612 SET_ELEMENT_TYPE(SIMPLE_STYPE),
613 TPMS_CLOCK_INFO_MARSHAL_REF,
614 (UINT16)(offsetof(TPMS_ATTEST, clockInfo)),
615 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(EIGHT_BYTES),
616 UINT64_MARSHAL_REF,
617 (UINT16)(offsetof(TPMS_ATTEST, firmwareVersion)),
618 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(1),
619 TPMU_ATTEST_MARSHAL_REF,
620 (UINT16)(offsetof(TPMS_ATTEST, attested))}},
621 // TPM2B_ATTEST_DATA
622 {TPM2B_MTYPE, Type28_MARSHAL_REF},
623 // TPMS_AUTH_COMMAND_DATA
624 {STRUCTURE_MTYPE, 4, {
625 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
626 TPMI_SH_AUTH_SESSION_MARSHAL_REF|NULL_FLAG,
627 (UINT16)(offsetof(TPMS_AUTH_COMMAND, sessionHandle)),
628 SET_ELEMENT_TYPE(SIMPLE_STYPE),
629 TPM2B_NONCE_MARSHAL_REF,
630 (UINT16)(offsetof(TPMS_AUTH_COMMAND, nonce)),
631 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(ONE_BYTES),
632 TPMA_SESSION_MARSHAL_REF,
633 (UINT16)(offsetof(TPMS_AUTH_COMMAND, sessionAttributes)),
634 SET_ELEMENT_TYPE(SIMPLE_STYPE),
635 TPM2B_AUTH_MARSHAL_REF,
636 (UINT16)(offsetof(TPMS_AUTH_COMMAND, hmac))}},
637 // TPMS_AUTH_RESPONSE_DATA
638 {STRUCTURE_MTYPE, 3, {
639 SET_ELEMENT_TYPE(SIMPLE_STYPE),
640 TPM2B_NONCE_MARSHAL_REF,
641 (UINT16)(offsetof(TPMS_AUTH_RESPONSE, nonce)),
642 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(ONE_BYTES),
643 TPMA_SESSION_MARSHAL_REF,
644 (UINT16)(offsetof(TPMS_AUTH_RESPONSE, sessionAttributes)),
645 SET_ELEMENT_TYPE(SIMPLE_STYPE),
646 TPM2B_AUTH_MARSHAL_REF,
647 (UINT16)(offsetof(TPMS_AUTH_RESPONSE, hmac))}},
648 // TPMI_TDES_KEY_BITS_DATA
649 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 1,
650 {128*TDES_128}},
651 // TPMI_AES_KEY_BITS_DATA
652 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 3,
653 {192*AES_192, 128*AES_128, 256*AES_256}},
654 // TPMI_SM4_KEY_BITS_DATA
655 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 1,
656 {128*SM4_128}},
657 // TPMI_CAMELLIA_KEY_BITS_DATA
658 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 3,
659 {192*CAMELLIA_192, 128*CAMELLIA_128, 256*CAMELLIA_256}},
660 // TPMU_SYM_KEY_BITS_DATA
727 SET_ELEMENT_TYPE(SIMPLE_STYPE),
728 TPM2B_AUTH_MARSHAL_REF,
729 (UINT16)(offsetof(TPMS_SENSITIVE_CREATE, userAuth)),
730 SET_ELEMENT_TYPE(SIMPLE_STYPE),
731 TPM2B_SENSITIVE_DATA_MARSHAL_REF,
732 (UINT16)(offsetof(TPMS_SENSITIVE_CREATE, data))}},
733 // TPM2B_SENSITIVE_CREATE_DATA
734 {TPM2BS_MTYPE,
735 (UINT8)(offsetof(TPM2B_SENSITIVE_CREATE, sensitive))|SIZE_EQUAL,
736 UINT16_MARSHAL_REF,
737 TPMS_SENSITIVE_CREATE_MARSHAL_REF},
738 // TPMS_SCHEME_HASH_DATA
739 {STRUCTURE_MTYPE, 1, {
740 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
741 TPMI_ALG_HASH_MARSHAL_REF,
742 (UINT16)(offsetof(TPMS_SCHEME_HASH, hashAlg))}},
743 // TPMS_SCHEME_ECDAA_DATA
744 {STRUCTURE_MTYPE, 2, {
745 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
746 TPMI_ALG_HASH_MARSHAL_REF,
747 (UINT16)(offsetof(TPMS_SCHEME_ECDAA, hashAlg)),
748 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
749 UINT16_MARSHAL_REF,
750 (UINT16)(offsetof(TPMS_SCHEME_ECDAA, count))}},
751 // TPMI_ALG_KEYEDHASH_SCHEME_DATA
752 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_VALUE,
753 {TPM_ALG_NULL,
754 RANGE(5, 10, UINT16),
755 ((ALG_HMAC << 0)|(ALG_XOR << 5))}},
756 // TPMS_SCHEME_XOR_DATA
757 {STRUCTURE_MTYPE, 2, {
758 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
759 TPMI_ALG_HASH_MARSHAL_REF,
760 (UINT16)(offsetof(TPMS_SCHEME_XOR, hashAlg)),
761 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
762 TPMI_ALG_KDF_MARSHAL_REF|NULL_FLAG,
763 (UINT16)(offsetof(TPMS_SCHEME_XOR, kdf))}},
764 // TPMU_SCHEME_KEYEDHASH_DATA
765 {3, 0, (UINT16)(offsetof(TPMU_SCHEME_KEYEDHASH_mst, marshalingTypes)),
766 {(UINT32)TPM_ALG_HMAC, (UINT32)TPM_ALG_XOR, (UINT32)TPM_ALG_NULL},
767 {(UINT16)(TPMS_SCHEME_HMAC_MARSHAL_REF),
768 (UINT16)(TPMS_SCHEME_XOR_MARSHAL_REF),
769 (UINT16)(UINT0_MARSHAL_REF)}
770 },
771 // TPMT_KEYEDHASH_SCHEME_DATA
772 {STRUCTURE_MTYPE, 2, {
773 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
774 TPMI_ALG_KEYEDHASH_SCHEME_MARSHAL_REF,
775 (UINT16)(offsetof(TPMT_KEYEDHASH_SCHEME, scheme)),
776 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
777 TPMU_SCHEME_KEYEDHASH_MARSHAL_REF,
778 (UINT16)(offsetof(TPMT_KEYEDHASH_SCHEME, details))}},
779 // TPMU_SIG_SCHEME_DATA
780 {8, 0, (UINT16)(offsetof(TPMU_SIG_SCHEME_mst, marshalingTypes)),
781 {(UINT32)TPM_ALG_ECDAA, (UINT32)TPM_ALG_RSASSA,
782 (UINT32)TPM_ALG_RSAPSS, (UINT32)TPM_ALG_ECDSA,
783 (UINT32)TPM_ALG_SM2, (UINT32)TPM_ALG_ECSCHNORR,
784 (UINT32)TPM_ALG_HMAC, (UINT32)TPM_ALG_NULL},
785 {(UINT16)(TPMS_SIG_SCHEME_ECDAA_MARSHAL_REF),
786 (UINT16)(TPMS_SIG_SCHEME_RSASSA_MARSHAL_REF),
787 (UINT16)(TPMS_SIG_SCHEME_RSAPSS_MARSHAL_REF),
788 (UINT16)(TPMS_SIG_SCHEME_ECDSA_MARSHAL_REF),
789 (UINT16)(TPMS_SIG_SCHEME_SM2_MARSHAL_REF),
790 (UINT16)(TPMS_SIG_SCHEME_ECSCHNORR_MARSHAL_REF),
791 (UINT16)(TPMS_SCHEME_HMAC_MARSHAL_REF),
792 (UINT16)(UINT0_MARSHAL_REF)}
793 },
794 // TPMT_SIG_SCHEME_DATA
795 {STRUCTURE_MTYPE, 2, {
796 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
797 TPMI_ALG_SIG_SCHEME_MARSHAL_REF,
798 (UINT16)(offsetof(TPMT_SIG_SCHEME, scheme)),
799 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
800 TPMU_SIG_SCHEME_MARSHAL_REF,
801 (UINT16)(offsetof(TPMT_SIG_SCHEME, details))}},
802 // TPMU_KDF_SCHEME_DATA
803 {5, 0, (UINT16)(offsetof(TPMU_KDF_SCHEME_mst, marshalingTypes)),
804 {(UINT32)TPM_ALG_MGF1, (UINT32)TPM_ALG_KDF1_SP800_56A,
805 (UINT32)TPM_ALG_KDF2, (UINT32)TPM_ALG_KDF1_SP800_108,
806 (UINT32)TPM_ALG_NULL},
807 {(UINT16)(TPMS_SCHEME_MGF1_MARSHAL_REF),
808 (UINT16)(TPMS_SCHEME_KDF1_SP800_56A_MARSHAL_REF),
809 (UINT16)(TPMS_SCHEME_KDF2_MARSHAL_REF),
810 (UINT16)(TPMS_SCHEME_KDF1_SP800_108_MARSHAL_REF),
811 (UINT16)(UINT0_MARSHAL_REF)}
812 },
813 // TPMT_KDF_SCHEME_DATA
814 {STRUCTURE_MTYPE, 2, {
815 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
816 TPMI_ALG_KDF_MARSHAL_REF,
817 (UINT16)(offsetof(TPMT_KDF_SCHEME, scheme)),
818 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
819 TPMU_KDF_SCHEME_MARSHAL_REF,
820 (UINT16)(offsetof(TPMT_KDF_SCHEME, details))}},
821 // TPMI_ALG_ASYM_SCHEME_DATA
822 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_VALUE,
823 {TPM_ALG_NULL,
824 RANGE(20, 29, UINT16),
825 ((ALG_RSASSA << 0) | (ALG_RSAES << 1) | (ALG_RSAPSS << 2) |
826 (ALG_OAEP << 3) | (ALG_ECDSA << 4) | (ALG_ECDH << 5) |
827 (ALG_ECDAA << 6) | (ALG_SM2 << 7) | (ALG_ECSCHNORR << 8) |
828 (ALG_ECMQV << 9))}},
829 // TPMU_ASYM_SCHEME_DATA
830 {11, 0, (UINT16)(offsetof(TPMU_ASYM_SCHEME_mst, marshalingTypes)),
831 {(UINT32)TPM_ALG_ECDH, (UINT32)TPM_ALG_ECMQV,
832 (UINT32)TPM_ALG_ECDAA, (UINT32)TPM_ALG_RSASSA,
833 (UINT32)TPM_ALG_RSAPSS, (UINT32)TPM_ALG_ECDSA,
834 (UINT32)TPM_ALG_SM2, (UINT32)TPM_ALG_ECSCHNORR,
835 (UINT32)TPM_ALG_RSAES, (UINT32)TPM_ALG_OAEP,
836 (UINT32)TPM_ALG_NULL},
837 {(UINT16)(TPMS_KEY_SCHEME_ECDH_MARSHAL_REF),
838 (UINT16)(TPMS_KEY_SCHEME_ECMQV_MARSHAL_REF),
839 (UINT16)(TPMS_SIG_SCHEME_ECDAA_MARSHAL_REF),
840 (UINT16)(TPMS_SIG_SCHEME_RSASSA_MARSHAL_REF),
841 (UINT16)(TPMS_SIG_SCHEME_RSAPSS_MARSHAL_REF),
842 (UINT16)(TPMS_SIG_SCHEME_ECDSA_MARSHAL_REF),
843 (UINT16)(TPMS_SIG_SCHEME_SM2_MARSHAL_REF),
844 (UINT16)(TPMS_SIG_SCHEME_ECSCHNORR_MARSHAL_REF),
845 (UINT16)(TPMS_ENC_SCHEME_RSAES_MARSHAL_REF),
846 (UINT16)(TPMS_ENC_SCHEME_OAEP_MARSHAL_REF),
847 (UINT16)(UINT0_MARSHAL_REF)}
848 },
849 // TPMI_ALG_RSA_SCHEME_DATA
850 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_VALUE,
851 {TPM_ALG_NULL,
852 RANGE(20, 23, UINT16),
853 ((ALG_RSASSA << 0)|(ALG_RSAES << 1)|(ALG_RSAPSS << 2)|(ALG_OAEP << 3))}},
854 // TPMT_RSA_SCHEME_DATA
855 {STRUCTURE_MTYPE, 2, {
856 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
857 TPMI_ALG_RSA_SCHEME_MARSHAL_REF,
858 (UINT16)(offsetof(TPMT_RSA_SCHEME, scheme)),
859 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
860 TPMU_ASYM_SCHEME_MARSHAL_REF,
861 (UINT16)(offsetof(TPMT_RSA_SCHEME, details))}},
862 // TPMI_ALG_RSA_DECRYPT_DATA
863 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_VALUE,
864 {TPM_ALG_NULL,
865 RANGE(21, 23, UINT16),
866 ((ALG_RSAES << 0)|(ALG_OAEP << 2))}},
867 // TPMT_RSA_DECRYPT_DATA
868 {STRUCTURE_MTYPE, 2, {
869 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
870 TPMI_ALG_RSA_DECRYPT_MARSHAL_REF,
871 (UINT16)(offsetof(TPMT_RSA_DECRYPT, scheme)),
872 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
873 TPMU_ASYM_SCHEME_MARSHAL_REF,
874 (UINT16)(offsetof(TPMT_RSA_DECRYPT, details))}},
875 // TPM2B_PUBLIC_KEY_RSA_DATA
876 {TPM2B_MTYPE, Type33_MARSHAL_REF},
877 // TPMI_RSA_KEY_BITS_DATA
878 {TABLE_MTYPE, TWO_BYTES, (UINT8)TPM_RC_VALUE, 3,
879 {3072*RSA_3072, 1024*RSA_1024, 2048*RSA_2048}},
880 // TPM2B_PRIVATE_KEY_RSA_DATA
881 {TPM2B_MTYPE, Type34_MARSHAL_REF},
882 // TPM2B_ECC_PARAMETER_DATA
883 {TPM2B_MTYPE, Type35_MARSHAL_REF},
884 // TPMS_ECC_POINT_DATA
885 {STRUCTURE_MTYPE, 2, {
886 SET_ELEMENT_TYPE(SIMPLE_STYPE),
887 TPM2B_ECC_PARAMETER_MARSHAL_REF,
888 (UINT16)(offsetof(TPMS_ECC_POINT, x)),
889 SET_ELEMENT_TYPE(SIMPLE_STYPE),
890 TPM2B_ECC_PARAMETER_MARSHAL_REF,
891 (UINT16)(offsetof(TPMS_ECC_POINT, y))}},
892 // TPM2B_ECC_POINT_DATA
893 {TPM2BS_MTYPE,
894 (UINT8)(offsetof(TPM2B_ECC_POINT, point))|SIZE_EQUAL,
895 UINT16_MARSHAL_REF,
896 TPMS_ECC_POINT_MARSHAL_REF},
897 // TPMI_ALG_ECC_SCHEME_DATA
898 {MIN_MAX_MTYPE, TWO_BYTES|TAKES_NULL|HAS_BITS, (UINT8)TPM_RC_SCHEME,
899 {TPM_ALG_NULL,
900 RANGE(24, 29, UINT16),
901 ((ALG_ECDSA << 0) | (ALG_ECDH << 1) | (ALG_ECDAA << 2) |
902 (ALG_SM2 << 3) | (ALG_ECSCHNORR << 4) | (ALG_ECMQV << 5))}},
903 // TPMI_ECC_CURVE_DATA
904 {MIN_MAX_MTYPE, TWO_BYTES|HAS_BITS, (UINT8)TPM_RC_CURVE,
905 {RANGE(1, 32, UINT16),
906 ((ECC_NIST_P192 << 0) | (ECC_NIST_P224 << 1) | (ECC_NIST_P256 << 2) |
907 (ECC_NIST_P384 << 3) | (ECC_NIST_P521 << 4) | (ECC_BN_P256 << 15) |
908 (ECC_BN_P638 << 16) | (ECC_SM2_P256 << 31))}},
909 // TPMT_ECC_SCHEME_DATA
910 {STRUCTURE_MTYPE, 2, {
911 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
912 TPMI_ALG_ECC_SCHEME_MARSHAL_REF,
913 (UINT16)(offsetof(TPMT_ECC_SCHEME, scheme)),
914 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
915 TPMU_ASYM_SCHEME_MARSHAL_REF,
916 (UINT16)(offsetof(TPMT_ECC_SCHEME, details))}},
917 // TPMS_ALGORITHM_DETAIL_ECC_DATA
918 {STRUCTURE_MTYPE, 11, {
919 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
920 TPM_ECC_CURVE_MARSHAL_REF,
921 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, curveID)),
922 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
923 UINT16_MARSHAL_REF,
924 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, keySize)),
925 SET_ELEMENT_TYPE(SIMPLE_STYPE),
926 TPMT_KDF_SCHEME_MARSHAL_REF|NULL_FLAG,
927 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, kdf)),
928 SET_ELEMENT_TYPE(SIMPLE_STYPE),
929 TPMT_ECC_SCHEME_MARSHAL_REF|NULL_FLAG,
930 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, sign)),
931 SET_ELEMENT_TYPE(SIMPLE_STYPE),
932 TPM2B_ECC_PARAMETER_MARSHAL_REF,
933 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, p)),
934 SET_ELEMENT_TYPE(SIMPLE_STYPE),
935 TPM2B_ECC_PARAMETER_MARSHAL_REF,
936 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, a)),
937 SET_ELEMENT_TYPE(SIMPLE_STYPE),
938 TPM2B_ECC_PARAMETER_MARSHAL_REF,
939 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, b)),
940 SET_ELEMENT_TYPE(SIMPLE_STYPE),
941 TPM2B_ECC_PARAMETER_MARSHAL_REF,
942 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, gX)),
943 SET_ELEMENT_TYPE(SIMPLE_STYPE),
944 TPM2B_ECC_PARAMETER_MARSHAL_REF,
945 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, gY)),
946 SET_ELEMENT_TYPE(SIMPLE_STYPE),
947 TPM2B_ECC_PARAMETER_MARSHAL_REF,
948 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, n)),
949 SET_ELEMENT_TYPE(SIMPLE_STYPE),
950 TPM2B_ECC_PARAMETER_MARSHAL_REF,
951 (UINT16)(offsetof(TPMS_ALGORITHM_DETAIL_ECC, h))}},
952 // TPMS_SIGNATURE_RSA_DATA
953 {STRUCTURE_MTYPE, 2, {
954 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
955 TPMI_ALG_HASH_MARSHAL_REF,
956 (UINT16)(offsetof(TPMS_SIGNATURE_RSA, hash)),
957 SET_ELEMENT_TYPE(SIMPLE_STYPE),
958 TPM2B_PUBLIC_KEY_RSA_MARSHAL_REF,
959 (UINT16)(offsetof(TPMS_SIGNATURE_RSA, sig))}},
960 // TPMS_SIGNATURE_ECC_DATA
961 {STRUCTURE_MTYPE, 3, {
962 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
963 TPMI_ALG_HASH_MARSHAL_REF,
964 (UINT16)(offsetof(TPMS_SIGNATURE_ECC, hash)),
965 SET_ELEMENT_TYPE(SIMPLE_STYPE),
966 TPM2B_ECC_PARAMETER_MARSHAL_REF,
967 (UINT16)(offsetof(TPMS_SIGNATURE_ECC, signatureR)),
968 SET_ELEMENT_TYPE(SIMPLE_STYPE),
969 TPM2B_ECC_PARAMETER_MARSHAL_REF,
970 (UINT16)(offsetof(TPMS_SIGNATURE_ECC, signatureS))}},
971 // TPMU_SIGNATURE_DATA
972 {8, 0, (UINT16)(offsetof(TPMU_SIGNATURE_mst, marshalingTypes)),
973 {(UINT32)TPM_ALG_ECDAA, (UINT32)TPM_ALG_RSASSA,
974 (UINT32)TPM_ALG_RSAPSS, (UINT32)TPM_ALG_ECDSA,
975 (UINT32)TPM_ALG_SM2, (UINT32)TPM_ALG_ECSCHNORR,
976 (UINT32)TPM_ALG_HMAC, (UINT32)TPM_ALG_NULL},
977 {(UINT16)(TPMS_SIGNATURE_ECDAA_MARSHAL_REF),
978 (UINT16)(TPMS_SIGNATURE_RSASSA_MARSHAL_REF),
979 (UINT16)(TPMS_SIGNATURE_RSAPSS_MARSHAL_REF),
980 (UINT16)(TPMS_SIGNATURE_ECDSA_MARSHAL_REF),
981 (UINT16)(TPMS_SIGNATURE_SM2_MARSHAL_REF),
982 (UINT16)(TPMS_SIGNATURE_ECSCHNORR_MARSHAL_REF),
983 (UINT16)(TPMT_HA_MARSHAL_REF),
984 (UINT16)(UINT0_MARSHAL_REF)}
985 },
986 // TPMT_SIGNATURE_DATA
987 {STRUCTURE_MTYPE, 2, {
988 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
989 TPMI_ALG_SIG_SCHEME_MARSHAL_REF,
990 (UINT16)(offsetof(TPMT_SIGNATURE, sigAlg)),
991 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
992 TPMU_SIGNATURE_MARSHAL_REF,
993 (UINT16)(offsetof(TPMT_SIGNATURE, signature))}},
994 // TPMU_ENCRYPTED_SECRET_DATA
995 {4, IS_ARRAY_UNION, (UINT16)(offsetof(TPMU_ENCRYPTED_SECRET_mst, marshalingTypes)),
996 {(UINT32)TPM_ALG_ECC, (UINT32)TPM_ALG_RSA,
997 (UINT32)TPM_ALG_SYMCIPHER, (UINT32)TPM_ALG_KEYEDHASH},
998 {(UINT16)(sizeof(TPMS_ECC_POINT)), (UINT16)(MAX_RSA_KEY_BYTES),
999 (UINT16)(sizeof(TPM2B_DIGEST)), (UINT16)(sizeof(TPM2B_DIGEST))}
1000 },
1001 // TPM2B_ENCRYPTED_SECRET_DATA
1002 {TPM2B_MTYPE, Type36_MARSHAL_REF},
1003 // TPMI_ALG_PUBLIC_DATA
1004 {MIN_MAX_MTYPE, TWO_BYTES|HAS_BITS, (UINT8)TPM_RC_TYPE,
1005 {RANGE(1, 37, UINT16),
1006 ((ALG_RSA << 0)|(ALG_KEYEDHASH << 7)),
1007 ((ALG_ECC << 2)|(ALG_SYMCIPHER << 4))}},
1008 // TPMU_PUBLIC_ID_DATA
1009 {4, 0, (UINT16)(offsetof(TPMU_PUBLIC_ID_mst, marshalingTypes)),
1010 {(UINT32)TPM_ALG_KEYEDHASH, (UINT32)TPM_ALG_SYMCIPHER,
1011 (UINT32)TPM_ALG_RSA, (UINT32)TPM_ALG_ECC},
1012 {(UINT16)(TPM2B_DIGEST_MARSHAL_REF),
1013 (UINT16)(TPM2B_DIGEST_MARSHAL_REF),
1014 (UINT16)(TPM2B_PUBLIC_KEY_RSA_MARSHAL_REF),
1015 (UINT16)(TPMS_ECC_POINT_MARSHAL_REF)}
1016 },
1017 // TPMS_KEYEDHASH_PARMS_DATA
1018 {STRUCTURE_MTYPE, 1, {
1019 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1020 TPMT_KEYEDHASH_SCHEME_MARSHAL_REF|NULL_FLAG,
1021 (UINT16)(offsetof(TPMS_KEYEDHASH_PARMS, scheme))}},
1022 // TPMS_RSA_PARMS_DATA
1023 {STRUCTURE_MTYPE, 4, {
1024 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1025 TPMT_SYM_DEF_OBJECT_MARSHAL_REF|NULL_FLAG,
1026 (UINT16)(offsetof(TPMS_RSA_PARMS, symmetric)),
1027 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1028 TPMT_RSA_SCHEME_MARSHAL_REF|NULL_FLAG,
1029 (UINT16)(offsetof(TPMS_RSA_PARMS, scheme)),
1030 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1031 TPMI_RSA_KEY_BITS_MARSHAL_REF,
1032 (UINT16)(offsetof(TPMS_RSA_PARMS, keyBits)),
1033 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1034 UINT32_MARSHAL_REF,
1035 (UINT16)(offsetof(TPMS_RSA_PARMS, exponent))}},
1036 // TPMS_ECC_PARMS_DATA
1037 {STRUCTURE_MTYPE, 4, {
1038 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1039 TPMT_SYM_DEF_OBJECT_MARSHAL_REF|NULL_FLAG,
1040 (UINT16)(offsetof(TPMS_ECC_PARMS, symmetric)),
1041 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1042 TPMT_ECC_SCHEME_MARSHAL_REF|NULL_FLAG,
1043 (UINT16)(offsetof(TPMS_ECC_PARMS, scheme)),
1044 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1045 TPMI_ECC_CURVE_MARSHAL_REF,
1046 (UINT16)(offsetof(TPMS_ECC_PARMS, curveID)),
1047 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1048 TPMT_KDF_SCHEME_MARSHAL_REF|NULL_FLAG,
1049 (UINT16)(offsetof(TPMS_ECC_PARMS, kdf))}},
1050 // TPMU_PUBLIC_PARMS_DATA
1051 {4, 0, (UINT16)(offsetof(TPMU_PUBLIC_PARMS_mst, marshalingTypes)),
1052 {(UINT32)TPM_ALG_KEYEDHASH, (UINT32)TPM_ALG_SYMCIPHER,
1053 (UINT32)TPM_ALG_RSA, (UINT32)TPM_ALG_ECC},
1054 {(UINT16)(TPMS_KEYEDHASH_PARMS_MARSHAL_REF),
1055 (UINT16)(TPMS_SYMCIPHER_PARMS_MARSHAL_REF),
1056 (UINT16)(TPMS_RSA_PARMS_MARSHAL_REF),
1057 (UINT16)(TPMS_ECC_PARMS_MARSHAL_REF)}
1058 },
1059 // TPMT_PUBLIC_PARMS_DATA
1060 {STRUCTURE_MTYPE, 2, {
1061 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1062 TPMI_ALG_PUBLIC_MARSHAL_REF,
1063 (UINT16)(offsetof(TPMT_PUBLIC_PARMS, type)),
1064 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
1065 TPMU_PUBLIC_PARMS_MARSHAL_REF,
1066 (UINT16)(offsetof(TPMT_PUBLIC_PARMS, parameters))}},
1067 // TPMT_PUBLIC_DATA
1068 {STRUCTURE_MTYPE, 6, {
1069 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1070 TPMI_ALG_PUBLIC_MARSHAL_REF,
1071 (UINT16)(offsetof(TPMT_PUBLIC, type)),
1072 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES)|ELEMENT_PROPAGATE,
1073 TPMI_ALG_HASH_MARSHAL_REF,
1074 (UINT16)(offsetof(TPMT_PUBLIC, nameAlg)),
1075 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1076 TPMA_OBJECT_MARSHAL_REF,
1077 (UINT16)(offsetof(TPMT_PUBLIC, objectAttributes)),
1078 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1079 TPM2B_DIGEST_MARSHAL_REF,
1080 (UINT16)(offsetof(TPMT_PUBLIC, authPolicy)),
1081 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
1082 TPMU_PUBLIC_PARMS_MARSHAL_REF,
1083 (UINT16)(offsetof(TPMT_PUBLIC, parameters)),
1084 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
1085 TPMU_PUBLIC_ID_MARSHAL_REF,
1086 (UINT16)(offsetof(TPMT_PUBLIC, unique))}},
1087 // TPM2B_PUBLIC_DATA
1088 {TPM2BS_MTYPE,
1089 (UINT8)(offsetof(TPM2B_PUBLIC, publicArea))|SIZE_EQUAL|ELEMENT_PROPAGATE,
1090 UINT16_MARSHAL_REF,
1091 TPMT_PUBLIC_MARSHAL_REF},
1092 // TPM2B_TEMPLATE_DATA
1093 {TPM2B_MTYPE, Type37_MARSHAL_REF},
1094 // TPM2B_PRIVATE_VENDOR_SPECIFIC_DATA
1095 {TPM2B_MTYPE, Type38_MARSHAL_REF},
1096 // TPMU_SENSITIVE_COMPOSITE_DATA
1097 {4, 0, (UINT16)(offsetof(TPMU_SENSITIVE_COMPOSITE_mst, marshalingTypes)),
1098 {(UINT32)TPM_ALG_RSA, (UINT32)TPM_ALG_ECC,
1099 (UINT32)TPM_ALG_KEYEDHASH, (UINT32)TPM_ALG_SYMCIPHER},
1100 {(UINT16)(TPM2B_PRIVATE_KEY_RSA_MARSHAL_REF),
1101 (UINT16)(TPM2B_ECC_PARAMETER_MARSHAL_REF),
1102 (UINT16)(TPM2B_SENSITIVE_DATA_MARSHAL_REF),
1103 (UINT16)(TPM2B_SYM_KEY_MARSHAL_REF)}
1104 },
1105 // TPMT_SENSITIVE_DATA
1106 {STRUCTURE_MTYPE, 4, {
1107 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1108 TPMI_ALG_PUBLIC_MARSHAL_REF,
1109 (UINT16)(offsetof(TPMT_SENSITIVE, sensitiveType)),
1110 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1111 TPM2B_AUTH_MARSHAL_REF,
1112 (UINT16)(offsetof(TPMT_SENSITIVE, authValue)),
1113 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1114 TPM2B_DIGEST_MARSHAL_REF,
1115 (UINT16)(offsetof(TPMT_SENSITIVE, seedValue)),
1116 SET_ELEMENT_TYPE(UNION_STYPE)|SET_ELEMENT_NUMBER(0),
1117 TPMU_SENSITIVE_COMPOSITE_MARSHAL_REF,
1118 (UINT16)(offsetof(TPMT_SENSITIVE, sensitive))}},
1119 // TPM2B_SENSITIVE_DATA
1120 {TPM2BS_MTYPE,
1121 (UINT8)(offsetof(TPM2B_SENSITIVE, sensitiveArea)),
1122 UINT16_MARSHAL_REF,
1123 TPMT_SENSITIVE_MARSHAL_REF},
1124 // TPM2B_PRIVATE_DATA
1125 {TPM2B_MTYPE, Type39_MARSHAL_REF},
1126 // TPM2B_ID_OBJECT_DATA
1127 {TPM2B_MTYPE, Type40_MARSHAL_REF},
1128 // TPMS_NV_PIN_COUNTER_PARAMETERS_DATA
1129 {STRUCTURE_MTYPE, 2, {
1130 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1131 UINT32_MARSHAL_REF,
1132 (UINT16)(offsetof(TPMS_NV_PIN_COUNTER_PARAMETERS, pinCount)),
1133 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1134 UINT32_MARSHAL_REF,
1135 (UINT16)(offsetof(TPMS_NV_PIN_COUNTER_PARAMETERS, pinLimit))}},
1136 // TPMA_NV_DATA
1137 {ATTRIBUTES_MTYPE, FOUR_BYTES, 0x01F00300},
1138 // TPMS_NV_PUBLIC_DATA
1139 {STRUCTURE_MTYPE, 5, {
1140 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1141 TPMI_RH_NV_INDEX_MARSHAL_REF,
1142 (UINT16)(offsetof(TPMS_NV_PUBLIC, nvIndex)),
1143 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1144 TPMI_ALG_HASH_MARSHAL_REF,
1145 (UINT16)(offsetof(TPMS_NV_PUBLIC, nameAlg)),
1146 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1147 TPMA_NV_MARSHAL_REF,
1148 (UINT16)(offsetof(TPMS_NV_PUBLIC, attributes)),
1149 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1150 TPM2B_DIGEST_MARSHAL_REF,
1151 (UINT16)(offsetof(TPMS_NV_PUBLIC, authPolicy)),
1152 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1153 Type41_MARSHAL_REF,
1154 (UINT16)(offsetof(TPMS_NV_PUBLIC, dataSize))}},
1155 // TPM2B_NV_PUBLIC_DATA
1156 {TPM2BS_MTYPE,
1157 (UINT8)(offsetof(TPM2B_NV_PUBLIC, nvPublic))|SIZE_EQUAL,
1158 UINT16_MARSHAL_REF,
1159 TPMS_NV_PUBLIC_MARSHAL_REF},
1160 // TPM2B_CONTEXT_SENSITIVE_DATA
1161 {TPM2B_MTYPE, Type42_MARSHAL_REF},
1162 // TPMS_CONTEXT_DATA_DATA
1163 {STRUCTURE_MTYPE, 2, {
1164 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1165 TPM2B_DIGEST_MARSHAL_REF,
1166 (UINT16)(offsetof(TPMS_CONTEXT_DATA, integrity)),
1167 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1168 TPM2B_CONTEXT_SENSITIVE_MARSHAL_REF,
1169 (UINT16)(offsetof(TPMS_CONTEXT_DATA, encrypted))}},
1170 // TPM2B_CONTEXT_DATA_DATA
1171 {TPM2B_MTYPE, Type43_MARSHAL_REF},
1172 // TPMS_CONTEXT_DATA
1173 {STRUCTURE_MTYPE, 4, {
1174 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(EIGHT_BYTES),
1175 UINT64_MARSHAL_REF,
1176 (UINT16)(offsetof(TPMS_CONTEXT, sequence)),
1177 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1178 TPMI_DH_SAVED_MARSHAL_REF,
1179 (UINT16)(offsetof(TPMS_CONTEXT, savedHandle)),
1180 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1181 TPMI_RH_HIERARCHY_MARSHAL_REF|NULL_FLAG,
1182 (UINT16)(offsetof(TPMS_CONTEXT, hierarchy)),
1183 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1184 TPM2B_CONTEXT_DATA_MARSHAL_REF,
1185 (UINT16)(offsetof(TPMS_CONTEXT, contextBlob))}},
1186 // TPMS_CREATION_DATA_DATA
1187 {STRUCTURE_MTYPE, 7, {
1188 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1189 TPML_PCR_SELECTION_MARSHAL_REF,
1190 (UINT16)(offsetof(TPMS_CREATION_DATA, pcrSelect)),
1191 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1192 TPM2B_DIGEST_MARSHAL_REF,
1193 (UINT16)(offsetof(TPMS_CREATION_DATA, pcrDigest)),
1194 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(ONE_BYTES),
1195 TPMA_LOCALITY_MARSHAL_REF,
1196 (UINT16)(offsetof(TPMS_CREATION_DATA, locality)),
1197 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(TWO_BYTES),
1198 TPM_ALG_ID_MARSHAL_REF,
1199 (UINT16)(offsetof(TPMS_CREATION_DATA, parentNameAlg)),
1200 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1201 TPM2B_NAME_MARSHAL_REF,
1202 (UINT16)(offsetof(TPMS_CREATION_DATA, parentName)),
1203 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1204 TPM2B_NAME_MARSHAL_REF,
1205 (UINT16)(offsetof(TPMS_CREATION_DATA, parentQualifiedName)),
1206 SET_ELEMENT_TYPE(SIMPLE_STYPE),
1207 TPM2B_DATA_MARSHAL_REF,
1208 (UINT16)(offsetof(TPMS_CREATION_DATA, outsideInfo))}},
1209 // TPM2B_CREATION_DATA_DATA
1210 {TPM2BS_MTYPE,
1211 (UINT8)(offsetof(TPM2B_CREATION_DATA, creationData))|SIZE_EQUAL,
1212 UINT16_MARSHAL_REF,
1213 TPMS_CREATION_DATA_MARSHAL_REF},
1214 // TPM_AT_DATA
1215 {TABLE_MTYPE, FOUR_BYTES, (UINT8)TPM_RC_VALUE, 4,
1216 {TPM_AT_ANY, TPM_AT_ERROR, TPM_AT_PV1, TPM_AT_VEND}},
1217 // TPMS_AC_OUTPUT_DATA
1218 {STRUCTURE_MTYPE, 2, {
1219 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1220 TPM_AT_MARSHAL_REF,
1221 (UINT16)(offsetof(TPMS_AC_OUTPUT, tag)),
1222 SET_ELEMENT_TYPE(SIMPLE_STYPE)|SET_ELEMENT_SIZE(FOUR_BYTES),
1223 UINT32_MARSHAL_REF,
1224 (UINT16)(offsetof(TPMS_AC_OUTPUT, data))}},
1225 // TPML_AC_CAPABILITIES_DATA
1226 {LIST_MTYPE,
1227 (UINT8)(offsetof(TPML_AC_CAPABILITIES, acCapabilities)),
1228 Type44_MARSHAL_REF,
1229 TPMS_AC_OUTPUT_ARRAY_MARSHAL_INDEX},
1230 // Type00_DATA
1231 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1232 {RANGE(0, sizeof(TPMU_HA), UINT16)}},
1233 // Type01_DATA
1234 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1235 {RANGE(0, sizeof(TPMT_HA), UINT16)}},
1236 // Type02_DATA
1237 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1238 {RANGE(0, 1024, UINT16)}},
1239 // Type03_DATA
1240 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1241 {RANGE(0, MAX_DIGEST_BUFFER, UINT16)}},
1242 // Type04_DATA
1243 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1244 {RANGE(0, MAX_NV_BUFFER_SIZE, UINT16)}},
1245 // Type05_DATA
1246 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1247 {RANGE(0, sizeof(UINT64), UINT16)}},
1248 // Type06_DATA
1249 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1250 {RANGE(0, MAX_SYM_BLOCK_SIZE, UINT16)}},
1251 // Type07_DATA
1252 {MIN_MAX_MTYPE, TWO_BYTES, (UINT8)TPM_RC_SIZE,
1253 {RANGE(0, sizeof(TPMU_NAME), UINT16)}},
1254 // Type08_DATA
9.11 MathOnByteBuffers.c
9.11.1 Introduction
This file contains implementation of the math functions that are performed with canonical integers in byte
buffers. The canonical integer is big-endian bytes.
1 #include "Tpm.h"
9.11.2 Functions
9.11.2.1 UnsignedCmpB
This function compare two unsigned values. The values are byte-aligned, big-endian numbers (e.g, a
hash).
2 LIB_EXPORT int
3 UnsignedCompareB(
4 UINT32 aSize, // IN: size of a
5 const BYTE *a, // IN: a
6 UINT32 bSize, // IN: size of b
7 const BYTE *b // IN: b
8 )
9 {
10 UINT32 i;
11 if(aSize > bSize)
12 return 1;
13 else if(aSize < bSize)
14 return -1;
15 else
16 {
17 for(i = 0; i < aSize; i++)
18 {
19 if(a[i] != b[i])
20 return (a[i] > b[i]) ? 1 : -1;
21 }
22 }
23 return 0;
24 }
9.11.2.2 SignedCompareB()
25 int
26 SignedCompareB(
27 const UINT32 aSize, // IN: size of a
28 const BYTE *a, // IN: a buffer
29 const UINT32 bSize, // IN: size of b
30 const BYTE *b // IN: b buffer
31 )
32 {
33 int signA, signB; // sign of a and b
34
35 // For positive or 0, sign_a is 1
36 // for negative, sign_a is 0
37 signA = ((a[0] & 0x80) == 0) ? 1 : 0;
38
39 // For positive or 0, sign_b is 1
40 // for negative, sign_b is 0
41 signB = ((b[0] & 0x80) == 0) ? 1 : 0;
42
43 if(signA != signB)
44 {
45 return signA - signB;
46 }
47 if(signA == 1)
48 // do unsigned compare function
49 return UnsignedCompareB(aSize, a, bSize, b);
50 else
51 // do unsigned compare the other way
52 return 0 - UnsignedCompareB(aSize, a, bSize, b);
53 }
9.11.2.3 ModExpB
This function is used to do modular exponentiation in support of RSA. The most typical uses are: c = m^e
mod n (RSA encrypt) and m = c^d mod n (RSA decrypt). When doing decryption, the e parameter of the
function will contain the private exponent d instead of the public exponent e.
If the results will not fit in the provided buffer, an error is returned (CRYPT_ERROR_UNDERFLOW). If
the results is smaller than the buffer, the results is de-normalized.
This version is intended for use with RSA and requires that m be less than n.
54 TPM_RC
55 ModExpB(
56 UINT32 cSize, // IN: the size of the output buffer. It will
57 // need to be the same size as the modulus
58 BYTE *c, // OUT: the buffer to receive the results
59 // (c->size must be set to the maximum size
60 // for the returned value)
61 const UINT32 mSize,
62 const BYTE *m, // IN: number to exponentiate
9.11.2.4 DivideB()
Divide an integer (n) by an integer (d) producing a quotient (q) and a remainder (r). If q or r is not needed,
then the pointer to them may be set to NULL.
92 LIB_EXPORT TPM_RC
93 DivideB(
94 const TPM2B *n, // IN: numerator
95 const TPM2B *d, // IN: denominator
96 TPM2B *q, // OUT: quotient
97 TPM2B *r // OUT: remainder
98 )
99 {
100 BN_MAX_INITIALIZED(bnN, n);
101 BN_MAX_INITIALIZED(bnD, d);
102 BN_MAX(bnQ);
103 BN_MAX(bnR);
104 //
105 // Do divide with converted values
106 BnDiv(bnQ, bnR, bnN, bnD);
107
108 // Convert the BIGNUM result back to 2B format using the size of the original
109 // number
110 if(q != NULL)
111 if(!BnTo2B(bnQ, q, q->size))
112 return TPM_RC_NO_RESULT;
113 if(r != NULL)
114 if(!BnTo2B(bnR, r, r->size))
115 return TPM_RC_NO_RESULT;
116 return TPM_RC_SUCCESS;
117 }
9.11.2.5 AdjustNumberB()
Remove/add leading zeros from a number in a TPM2B. Will try to make the number by adding or
removing leading zeros. If the number is larger than the requested size, it will make the number as small
as possible. Setting requestedSize to zero is equivalent to requesting that the number be normalized.
118 UINT16
119 AdjustNumberB(
120 TPM2B *num,
121 UINT16 requestedSize
122 )
123 {
124 BYTE *from;
125 UINT16 i;
126 // See if number is already the requested size
127 if(num->size == requestedSize)
128 return requestedSize;
129 from = num->buffer;
130 if (num->size > requestedSize)
131 {
132 // This is a request to shift the number to the left (remove leading zeros)
133 // Find the first non-zero byte. Don't look past the point where removing
134 // more zeros would make the number smaller than requested, and don't throw
135 // away any significant digits.
136 for(i = num->size; *from == 0 && i > requestedSize; from++, i--);
137 if(i < num->size)
138 {
139 num->size = i;
140 MemoryCopy(num->buffer, from, i);
141 }
142 }
143 // This is a request to shift the number to the right (add leading zeros)
144 else
145 {
146 MemoryCopy(&num->buffer[requestedSize - num->size], num->buffer, num->size);
147 MemorySet(num->buffer, 0, requestedSize- num->size);
148 num->size = requestedSize;
149 }
150 return num->size;
151 }
9.11.2.6 ShiftLeft()
This function shifts a byte buffer (a TPM2B) one byte to the left. That is, the most significant bit of the
most significant byte is lost.
152 TPM2B *
153 ShiftLeft(
154 TPM2B *value // IN/OUT: value to shift and shifted value out
155 )
156 {
157 UINT16 count = value->size;
158 BYTE *buffer = value->buffer;
159 if(count > 0)
160 {
161 for(count -= 1; count > 0; buffer++, count--)
162 {
163 buffer[0] = (buffer[0] << 1) + ((buffer[1] & 0x80) ? 1 : 0);
164 }
165 *buffer <<= 1;
166 }
167 return value;
168 }
9.12 Memory.c
9.12.1 Description
This file contains a set of miscellaneous memory manipulation routines. Many of the functions have the
same semantics as functions defined in string.h. Those functions are not used directly in the TPM
because they are not safe
This version uses string.h after adding guards. This is because the math libraries invariably use those
functions so it is not practical to prevent those library functions from being pulled into the build.
1 #include "Tpm.h"
2 #include "Memory_fp.h"
9.12.3 Functions
9.12.3.1 MemoryCopy()
This is an alias for memmove. This is used in place of memcpy because some of the moves may overlap
and rather than try to make sure that memmove is used when necessary, it is always used.
3 void
4 MemoryCopy(
5 void *dest,
6 const void *src,
7 int sSize
8 )
9 {
10 if(dest != src)
11 memmove(dest, src, sSize);
12 }
9.12.3.2 MemoryEqual()
This function indicates if two buffers have the same values in the indicated number of bytes.
13 BOOL
14 MemoryEqual(
15 const void *buffer1, // IN: compare buffer1
16 const void *buffer2, // IN: compare buffer2
17 unsigned int size // IN: size of bytes being compared
18 )
19 {
20 BYTE equal = 0;
21 const BYTE *b1 = (BYTE *)buffer1;
22 const BYTE *b2 = (BYTE *)buffer2;
23 //
24 // Compare all bytes so that there is no leakage of information
25 // due to timing differences.
26 for(; size > 0; size--)
9.12.3.3 MemoryCopy2B()
This function copies a TPM2B. This can be used when the TPM2B types are the same or different.
This function returns the number of octets in the data buffer of the TPM2B.
30 LIB_EXPORT INT16
31 MemoryCopy2B(
32 TPM2B *dest, // OUT: receiving TPM2B
33 const TPM2B *source, // IN: source TPM2B
34 unsigned int dSize // IN: size of the receiving buffer
35 )
36 {
37 pAssert(dest != NULL);
38 if(source == NULL)
39 dest->size = 0;
40 else
41 {
42 pAssert(source->size <= dSize);
43 MemoryCopy(dest->buffer, source->buffer, source->size);
44 dest->size = source->size;
45 }
46 return dest->size;
47 }
9.12.3.4 MemoryConcat2B()
This function will concatenate the buffer contents of a TPM2B to an the buffer contents of another TPM2B
and adjust the size accordingly (a := (a | b)).
48 void
49 MemoryConcat2B(
50 TPM2B *aInOut, // IN/OUT: destination 2B
51 TPM2B *bIn, // IN: second 2B
52 unsigned int aMaxSize // IN: The size of aInOut.buffer (max values for
53 // aInOut.size)
54 )
55 {
56 pAssert(bIn->size <= aMaxSize - aInOut->size);
57 MemoryCopy(&aInOut->buffer[aInOut->size], &bIn->buffer, bIn->size);
58 aInOut->size = aInOut->size + bIn->size;
59 return;
60 }
9.12.3.5 MemoryEqual2B()
This function will compare two TPM2B structures. To be equal, they need to be the same size and the
buffer contexts need to be the same in all octets.
61 BOOL
62 MemoryEqual2B(
9.12.3.6 MemorySet()
This function will set all the octets in the specified memory range to the specified octet value.
NOTE: A previous version had an additional parameter (dSize) that was intended to make sure that the destination
would not be overrun. The problem is that, in use, all that was happening was that the value of size was used
for dSize so there was no benefit in the extra parameter.
71 void
72 MemorySet(
73 void *dest,
74 int value,
75 size_t size
76 )
77 {
78 memset(dest, value, size);
79 }
9.12.3.7 MemoryPad2B()
80 void
81 MemoryPad2B(
82 TPM2B *b,
83 UINT16 newSize
84 )
85 {
86 MemorySet(&b->buffer[b->size], 0, newSize - b->size);
87 b->size = newSize;
88 }
9.12.3.8 Uint16ToByteArray()
89 void
90 Uint16ToByteArray(
91 UINT16 i,
92 BYTE *a
93 )
94 {
95 a[1] = (BYTE)(i); i >>= 8;
96 a[0] = (BYTE)(i);
97 }
9.12.3.9 Uint32ToByteArray()
98 void
99 Uint32ToByteArray(
100 UINT32 i,
101 BYTE *a
102 )
103 {
104 a[3] = (BYTE)(i); i >>= 8;
105 a[2] = (BYTE)(i); i >>= 8;
106 a[1] = (BYTE)(i); i >>= 8;
107 a[0] = (BYTE)(i);
108 }
9.12.3.10 Uint64ToByteArray()
109 void
110 Uint64ToByteArray(
111 UINT64 i,
112 BYTE *a
113 )
114 {
115 a[7] = (BYTE)(i); i >>= 8;
116 a[6] = (BYTE)(i); i >>= 8;
117 a[5] = (BYTE)(i); i >>= 8;
118 a[4] = (BYTE)(i); i >>= 8;
119 a[3] = (BYTE)(i); i >>= 8;
120 a[2] = (BYTE)(i); i >>= 8;
121 a[1] = (BYTE)(i); i >>= 8;
122 a[0] = (BYTE)(i);
123 }
9.12.3.11 ByteArrayToUint8()
Function to write a UINT8 to a byte array. This is included for completeness and to allow certain macro
expansions
124 UINT8
125 ByteArrayToUint8(
126 BYTE *a
127 )
128 {
129 return *a;
130 }
9.12.3.12 ByteArrayToUint16()
131 UINT16
132 ByteArrayToUint16(
133 BYTE *a
134 )
135 {
136 return ((UINT16)a[0] << 8) + a[1];
137 }
9.12.3.13 ByteArrayToUint32()
138 UINT32
139 ByteArrayToUint32(
140 BYTE *a
141 )
142 {
143 return (UINT32)((((((UINT32)a[0] << 8) + a[1]) << 8) + (UINT32)a[2]) << 8) + a[3];
144 }
9.12.3.14 ByteArrayToUint64()
145 UINT64
146 ByteArrayToUint64(
147 BYTE *a
148 )
149 {
150 return (((UINT64)BYTE_ARRAY_TO_UINT32(a)) << 32) + BYTE_ARRAY_TO_UINT32(&a[4]);
151 }
9.13 Power.c
9.13.1 Description
This file contains functions that receive the simulated power state transitions of the TPM.
1 #define POWER_C
2 #include "Tpm.h"
9.13.3 Functions
9.13.3.1 TPMInit()
3 void
4 TPMInit(
5 void
6 )
7 {
8 // Set state as not initialized. This means that Startup is required
9 g_initialized = FALSE;
10 return;
11 }
9.13.3.2 TPMRegisterStartup()
This function registers the fact that the TPM has been initialized (a TPM2_Startup() has completed
successfully).
12 BOOL
13 TPMRegisterStartup(
14 void
15 )
16 {
17 g_initialized = TRUE;
18 return TRUE;
19 }
9.13.3.3 TPMIsStarted()
Indicates if the TPM has been initialized (a TPM2_Startup() has completed successfully after a
_TPM_Init()).
20 BOOL
21 TPMIsStarted(
22 void
23 )
24 {
25 return g_initialized;
26 }
9.14 PropertyCap.c
9.14.1 Description
This file contains the functions that are used for accessing the TPM_CAP_TPM_PROPERTY values.
9.14.2 Includes
1 #include "Tpm.h"
9.14.3 Functions
9.14.3.1 TPMPropertyIsDefined()
This function accepts a property selection and, if so, sets value to the value of the property.
All the fixed values are vendor dependent or determined by a platform-specific specification. The values
in the table below are examples and should be changed by the vendor.
2 static BOOL
3 TPMPropertyIsDefined(
4 TPM_PT property, // IN: property
5 UINT32 *value // OUT: property value
6 )
7 {
8 switch(property)
9 {
10 case TPM_PT_FAMILY_INDICATOR:
11 // from the title page of the specification
12 // For this specification, the value is "2.0".
13 *value = TPM_SPEC_FAMILY;
14 break;
15 case TPM_PT_LEVEL:
16 // from the title page of the specification
17 *value = TPM_SPEC_LEVEL;
18 break;
19 case TPM_PT_REVISION:
20 // from the title page of the specification
21 *value = TPM_SPEC_VERSION;
22 break;
23 case TPM_PT_DAY_OF_YEAR:
24 // computed from the date value on the title page of the specification
25 *value = TPM_SPEC_DAY_OF_YEAR;
26 break;
27 case TPM_PT_YEAR:
28 // from the title page of the specification
29 *value = TPM_SPEC_YEAR;
30 break;
31 case TPM_PT_MANUFACTURER:
32 // vendor ID unique to each TPM manufacturer
33 *value = BYTE_ARRAY_TO_UINT32(MANUFACTURER);
34 break;
35 case TPM_PT_VENDOR_STRING_1:
36 // first four characters of the vendor ID string
37 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_1);
38 break;
39 case TPM_PT_VENDOR_STRING_2:
40 // second four characters of the vendor ID string
41 #ifdef VENDOR_STRING_2
42 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_2);
43 #else
44 *value = 0;
45 #endif
46 break;
47 case TPM_PT_VENDOR_STRING_3:
48 // third four characters of the vendor ID string
49 #ifdef VENDOR_STRING_3
50 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_3);
51 #else
52 *value = 0;
53 #endif
54 break;
55 case TPM_PT_VENDOR_STRING_4:
56 // fourth four characters of the vendor ID string
57 #ifdef VENDOR_STRING_4
58 *value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_4);
59 #else
60 *value = 0;
61 #endif
62 break;
63 case TPM_PT_VENDOR_TPM_TYPE:
64 // vendor-defined value indicating the TPM model
65 *value = 1;
66 break;
67 case TPM_PT_FIRMWARE_VERSION_1:
68 // more significant 32-bits of a vendor-specific value
69 *value = gp.firmwareV1;
70 break;
71 case TPM_PT_FIRMWARE_VERSION_2:
72 // less significant 32-bits of a vendor-specific value
73 *value = gp.firmwareV2;
74 break;
75 case TPM_PT_INPUT_BUFFER:
76 // maximum size of TPM2B_MAX_BUFFER
77 *value = MAX_DIGEST_BUFFER;
78 break;
79 case TPM_PT_HR_TRANSIENT_MIN:
80 // minimum number of transient objects that can be held in TPM
81 // RAM
82 *value = MAX_LOADED_OBJECTS;
83 break;
84 case TPM_PT_HR_PERSISTENT_MIN:
85 // minimum number of persistent objects that can be held in
86 // TPM NV memory
87 // In this implementation, there is no minimum number of
88 // persistent objects.
89 *value = MIN_EVICT_OBJECTS;
90 break;
91 case TPM_PT_HR_LOADED_MIN:
92 // minimum number of authorization sessions that can be held in
93 // TPM RAM
94 *value = MAX_LOADED_SESSIONS;
95 break;
96 case TPM_PT_ACTIVE_SESSIONS_MAX:
97 // number of authorization sessions that may be active at a time
98 *value = MAX_ACTIVE_SESSIONS;
99 break;
100 case TPM_PT_PCR_COUNT:
101 // number of PCR implemented
102 *value = IMPLEMENTATION_PCR;
103 break;
302 break;
303 }
304 case TPM_PT_VENDOR_COMMANDS:
305 // number of vendor commands that are implemented
306 *value = VENDOR_COMMAND_ARRAY_SIZE;
307 break;
308 case TPM_PT_NV_BUFFER_MAX:
309 // Maximum data size in an NV write command
310 *value = MAX_NV_BUFFER_SIZE;
311 break;
312 case TPM_PT_MODES:
313 #if FIPS_COMPLIANT
314 *value = 1;
315 #else
316 *value = 0;
317 #endif
318 break;
319 case TPM_PT_MAX_CAP_BUFFER:
320 *value = MAX_CAP_BUFFER;
321 break;
322
323 // Start of variable commands
324 case TPM_PT_PERMANENT:
325 // TPMA_PERMANENT
326 {
327 union {
328 TPMA_PERMANENT attr;
329 UINT32 u32;
330 } flags = { TPMA_ZERO_INITIALIZER() };
331 if(gp.ownerAuth.t.size != 0)
332 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, ownerAuthSet);
333 if(gp.endorsementAuth.t.size != 0)
334 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, endorsementAuthSet);
335 if(gp.lockoutAuth.t.size != 0)
336 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, lockoutAuthSet);
337 if(gp.disableClear)
338 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, disableClear);
339 if(gp.failedTries >= gp.maxTries)
340 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, inLockout);
341 // In this implementation, EPS is always generated by TPM
342 SET_ATTRIBUTE(flags.attr, TPMA_PERMANENT, tpmGeneratedEPS);
343
344 // Note: For a LSb0 machine, the bits in a bit field are in the correct
345 // order even if the machine is MSB0. For a MSb0 machine, a TPMA will
346 // be an integer manipulated by masking (USE_BIT_FIELD_STRUCTURES will
347 // be NO) so the bits are manipulate correctly.
348 *value = flags.u32;
349 break;
350 }
351 case TPM_PT_STARTUP_CLEAR:
352 // TPMA_STARTUP_CLEAR
353 {
354 union {
355 TPMA_STARTUP_CLEAR attr;
356 UINT32 u32;
357 } flags = { TPMA_ZERO_INITIALIZER() };
358 //
359 if(g_phEnable)
360 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnable);
361 if(gc.shEnable)
362 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, shEnable);
363 if(gc.ehEnable)
364 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, ehEnable);
365 if(gc.phEnableNV)
366 SET_ATTRIBUTE(flags.attr, TPMA_STARTUP_CLEAR, phEnableNV);
367 if(g_prevOrderlyState != SU_NONE_VALUE)
9.14.3.2 TPMCapGetProperties()
This function is used to get the TPM_PT values. The search of properties will start at property and
continue until propertyList has as many values as will fit, or the last property has been reported, or the list
has as many values as requested in count.
479 TPMI_YES_NO
480 TPMCapGetProperties(
481 TPM_PT property, // IN: the starting TPM property
482 UINT32 count, // IN: maximum number of returned
483 // properties
484 TPML_TAGGED_TPM_PROPERTY *propertyList // OUT: property list
485 )
486 {
487 TPMI_YES_NO more = NO;
488 UINT32 i;
489 UINT32 nextGroup;
490
491 // initialize output property list
492 propertyList->count = 0;
493
494 // maximum count of properties we may return is MAX_PCR_PROPERTIES
495 if(count > MAX_TPM_PROPERTIES) count = MAX_TPM_PROPERTIES;
496
497 // if property is less than PT_FIXED, start from PT_FIXED
498 if(property < PT_FIXED)
499 property = PT_FIXED;
500 // There is only the fixed and variable groups with the variable group coming
501 // last
502 if(property >= (PT_VAR + PT_GROUP))
503 return more;
504
505 // Don't read past the end of the selected group
506 nextGroup = ((property / PT_GROUP) * PT_GROUP) + PT_GROUP;
507
508 // Scan through the TPM properties of the requested group.
509 for(i = property; i < nextGroup; i++)
510 {
511 UINT32 value;
512 // if we have hit the end of the group, quit
513 if(i != property && ((i % PT_GROUP) == 0))
514 break;
515 if(TPMPropertyIsDefined((TPM_PT)i, &value))
516 {
517 if(propertyList->count < count)
518 {
519 // If the list is not full, add this property
520 propertyList->tpmProperty[propertyList->count].property =
521 (TPM_PT)i;
522 propertyList->tpmProperty[propertyList->count].value = value;
523 propertyList->count++;
524 }
525 else
526 {
527 // If the return list is full but there are more properties
528 // available, set the indication and exit the loop.
529 more = YES;
530 break;
531 }
532 }
533 }
534 return more;
535 }
9.15 Response.c
9.15.1 Description
This file contains the common code for building a response header, including setting the size of the
structure. command may be NULL if result is not TPM_RC_SUCCESS.
1 #include "Tpm.h"
9.15.3 BuildResponseHeader()
Adds the response header to the response. It will update command->parameterSize to indicate the total
size of the response.
2 void
3 BuildResponseHeader(
4 COMMAND *command, // IN: main control structure
5 BYTE *buffer, // OUT: the output buffer
6 TPM_RC result // IN: the response code
7 )
8 {
9 TPM_ST tag;
10 UINT32 size;
11
12 if(result != TPM_RC_SUCCESS)
13 {
14 tag = TPM_ST_NO_SESSIONS;
15 size = 10;
16 }
17 else
18 {
19 tag = command->tag;
20 // Compute the overall size of the response
21 size = STD_RESPONSE_HEADER + command->handleNum * sizeof(TPM_HANDLE);
22 size += command->parameterSize;
23 size += (command->tag == TPM_ST_SESSIONS) ?
24 command->authSize + sizeof(UINT32) : 0;
25 }
26 TPM_ST_Marshal(&tag, &buffer, NULL);
27 UINT32_Marshal(&size, &buffer, NULL);
28 TPM_RC_Marshal(&result, &buffer, NULL);
29 if(result == TPM_RC_SUCCESS)
30 {
31 if(command->handleNum > 0)
32 TPM_HANDLE_Marshal(&command->handles[0], &buffer, NULL);
33 if(tag == TPM_ST_SESSIONS)
34 UINT32_Marshal((UINT32 *)&command->parameterSize, &buffer, NULL);
35 }
36 command->parameterSize = size;
37 }
9.16 ResponseCodeProcessing.c
9.16.1 Description
This file contains the miscellaneous functions for processing response codes.
1 #include "Tpm.h"
9.16.3 RcSafeAddToResult()
Adds a modifier to a response code as long as the response code allows a modifier and no modifier has
already been added.
2 TPM_RC
3 RcSafeAddToResult(
4 TPM_RC responseCode,
5 TPM_RC modifier
6 )
7 {
8 if((responseCode & RC_FMT1) && !(responseCode & 0xf40))
9 return responseCode + modifier;
10 else
11 return responseCode;
12 }
9.17 TpmFail.c
1 #define TPM_FAIL_C
2 #include "Tpm.h"
3 #include <assert.h>
On MS C compiler, can save the alignment state and set the alignment to 1 for the duration of the
TpmTypes.h include. This will avoid a lot of alignment warnings from the compiler for the unaligned
structures. The alignment of the structures is not important as this function does not use any of the
structures in TpmTypes.h and only include it for the #defines of the capabilities, properties, and command
code values.
4 #include "TpmTypes.h"
9.17.2 Typedefs
These defines are used primarily for sizing of the local response buffer.
5 typedef struct
6 {
7 TPM_ST tag;
8 UINT32 size;
9 TPM_RC code;
10 } HEADER;
11 typedef struct
12 {
13 BYTE tag[sizeof(TPM_ST)];
14 BYTE size[sizeof(UINT32)];
15 BYTE code[sizeof(TPM_RC)];
16 } PACKED_HEADER;
17 typedef struct
18 {
19 BYTE size[sizeof(UINT16)];
20 struct
21 {
22 BYTE function[sizeof(UINT32)];
23 BYTE line[sizeof(UINT32)];
24 BYTE code[sizeof(UINT32)];
25 } values;
26 BYTE returnCode[sizeof(TPM_RC)];
27 } GET_TEST_RESULT_PARAMETERS;
28 typedef struct
29 {
30 BYTE moreData[sizeof(TPMI_YES_NO)];
31 BYTE capability[sizeof(TPM_CAP)]; // Always TPM_CAP_TPM_PROPERTIES
32 BYTE tpmProperty[sizeof(TPML_TAGGED_TPM_PROPERTY)];
33 } GET_CAPABILITY_PARAMETERS;
34 typedef struct
35 {
36 BYTE header[sizeof(PACKED_HEADER)];
37 BYTE getTestResult[sizeof(GET_TEST_RESULT_PARAMETERS)];
38 } TEST_RESPONSE;
39 typedef struct
40 {
41 BYTE header[sizeof(PACKED_HEADER)];
42 BYTE getCap[sizeof(GET_CAPABILITY_PARAMETERS)];
43 } CAPABILITY_RESPONSE;
44 typedef union
45 {
46 BYTE test[sizeof(TEST_RESPONSE)];
47 BYTE cap[sizeof(CAPABILITY_RESPONSE)];
48 } RESPONSES;
Buffer to hold the responses. This may be a little larger than required due to padding that a compiler
might add.
NOTE: This is not in Global.c because of the specialized data definitions above. Since the data contained in this
structure is not relevant outside of the execution of a single command (when the TPM is in failure mode. There
is no compelling reason to move all the typedefs to Global.h and this structure to Global.c.
9.17.3.1 MarshalUint16()
52 static INT32
53 MarshalUint16(
54 UINT16 integer,
55 BYTE **buffer
56 )
57 {
58 UINT16_TO_BYTE_ARRAY(integer, *buffer);
59 *buffer += 2;
60 return 2;
61 }
9.17.3.2 MarshalUint32()
62 static INT32
63 MarshalUint32(
64 UINT32 integer,
65 BYTE **buffer
66 )
67 {
68 UINT32_TO_BYTE_ARRAY(integer, *buffer);
69 *buffer += 4;
70 return 4;
71 }
9.17.3.3 Unmarshal32()
83 }
9.17.3.4 Unmarshal16()
9.17.4.1 SetForceFailureMode()
96 #if SIMULATION
97 LIB_EXPORT void
98 SetForceFailureMode(
99 void
100 )
101 {
102 g_forceFailureMode = TRUE;
103 return;
104 }
105 #endif
9.17.4.2 TpmLogFailure()
This function saves the failure values when the code will continue to operate. It if similar to TpmFail() but
returns to the caller. The assumption is that the caller will propagate a failure back up the stack.
106 void
107 TpmLogFailure(
108 #if FAIL_TRACE
109 const char *function,
110 int line,
111 #endif
112 int code
113 )
114 {
115 // Save the values that indicate where the error occurred.
116 // On a 64-bit machine, this may truncate the address of the string
117 // of the function name where the error occurred.
118 #if FAIL_TRACE
119 s_failFunction = (UINT32)(ptrdiff_t)function;
120 s_failLine = line;
121 #else
122 s_failFunction = 0;
123 s_failLine = 0;
124 #endif
125 s_failCode = code;
126
127 // We are in failure mode
9.17.4.3 TpmFail()
This function is called by TPM.lib when a failure occurs. It will set up the failure values to be returned on
TPM2_GetTestResult().
9.17.4.4 TpmFailureMode
This function is called by the interface code when the platform is in failure mode.
169 void
170 TpmFailureMode(
171 unsigned int inRequestSize, // IN: command buffer size
172 unsigned char *inRequest, // IN: command buffer
173 unsigned int *outResponseSize, // OUT: response buffer size
174 unsigned char **outResponse // OUT: response buffer
175 )
176 {
177 UINT32 marshalSize;
178 UINT32 capability;
179 HEADER header; // unmarshaled command header
312 pt = 0;
313 #endif
314 break;
315 default: // TPM_PT_FIRMWARE_VERSION_2:
316 // the less significant 32-bits of a vendor-specific value
317 // indicating the version of the firmware
318 #ifdef FIRMWARE_V2
319 pt = FIRMWARE_V2;
320 #else
321 pt = 0;
322 #endif
323 break;
324 }
325 marshalSize += MarshalUint32(pt, &buffer);
326 break;
327 default: // default for switch (cc)
328 goto FailureModeReturn;
329 }
330 // Now do the header
331 buffer = response;
332 marshalSize = marshalSize + 10; // Add the header size to the
333 // stuff already marshaled
334 MarshalUint16(TPM_ST_NO_SESSIONS, &buffer); // structure tag
335 MarshalUint32(marshalSize, &buffer); // responseSize
336 MarshalUint32(TPM_RC_SUCCESS, &buffer); // response code
337
338 *outResponseSize = marshalSize;
339 *outResponse = (unsigned char *)&response;
340 return;
341 FailureModeReturn:
342 buffer = response;
343 marshalSize = MarshalUint16(TPM_ST_NO_SESSIONS, &buffer);
344 marshalSize += MarshalUint32(10, &buffer);
345 marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer);
346 *outResponseSize = marshalSize;
347 *outResponse = (unsigned char *)response;
348 return;
349 }
9.17.4.5 UnmarshalFail()
This is a stub that is used to catch an attempt to unmarshal an entry that is not defined. Don't ever expect
this to be called but...
350 void
351 UnmarshalFail(
352 void *type,
353 BYTE **buffer,
354 INT32 *size
355 )
356 {
357 NOT_REFERENCED(type);
358 NOT_REFERENCED(buffer);
359 NOT_REFERENCED(size);
360 FAIL(FATAL_ERROR_INTERNAL);
361 }
10 Cryptographic Functions
10.1 Headers
10.1.1 BnValues.h
10.1.1.1 Introduction
This file contains the definitions needed for defining the internal BIGNUM structure. A BIGNUM is a
pointer to a structure. The structure has three fields. The last field is and array (d) of crypt_uword_t. Each
word is in machine format (big- or little-endian) with the words in ascending significance (i.e. words in
little-endian order). This is the order that seems to be used in every big number library in the worlds, so...
The first field in the structure (allocated) is the number of words in d. This is the upper limit on the size of
the number that can be held in the structure. This differs from libraries like OpenSSL as this is not
intended to deal with numbers of arbitrary size; just numbers that are needed to deal with the algorithms
that are defined in the TPM implementation.
The second field in the structure (size) is the number of significant words in n. When this number is zero,
the number is zero. The word at used-1 should never be zero. All words between d[size] and d[allocated-
1] should be zero.
10.1.1.2 Defines
1 #ifndef _BN_NUMBERS_H
2 #define _BN_NUMBERS_H
3 #if RADIX_BITS == 64
4 # define RADIX_LOG2 6
5 #elif RADIX_BITS == 32
6 #define RADIX_LOG2 5
7 #else
8 # error "Unsupported radix"
9 #endif
10 #define RADIX_MOD(x) ((x) & ((1 << RADIX_LOG2) - 1))
11 #define RADIX_DIV(x) ((x) >> RADIX_LOG2)
12 #define RADIX_MASK ((((crypt_uword_t)1) << RADIX_LOG2) - 1)
13 #define BITS_TO_CRYPT_WORDS(bits) RADIX_DIV((bits) + (RADIX_BITS - 1))
14 #define BYTES_TO_CRYPT_WORDS(bytes) BITS_TO_CRYPT_WORDS(bytes * 8)
15 #define SIZE_IN_CRYPT_WORDS(thing) BYTES_TO_CRYPT_WORDS(sizeof(thing))
16 #if RADIX_BITS == 64
17 #define SWAP_CRYPT_WORD(x) REVERSE_ENDIAN_64(x)
18 typedef uint64_t crypt_uword_t;
19 typedef int64_t crypt_word_t;
20 # define TO_CRYPT_WORD_64 BIG_ENDIAN_BYTES_TO_UINT64
21 # define TO_CRYPT_WORD_32(a, b, c, d) TO_CRYPT_WORD_64(0, 0, 0, 0, a, b, c, d)
22 #elif RADIX_BITS == 32
23 # define SWAP_CRYPT_WORD(x) REVERSE_ENDIAN_32((x))
24 typedef uint32_t crypt_uword_t;
25 typedef int32_t crypt_word_t;
26 # define TO_CRYPT_WORD_64(a, b, c, d, e, f, g, h) \
27 BIG_ENDIAN_BYTES_TO_UINT32(e, f, g, h), \
28 BIG_ENDIAN_BYTES_TO_UINT32(a, b, c, d)
29 #endif
30 #define MAX_CRYPT_UWORD (~((crypt_uword_t)0))
31 #define MAX_CRYPT_WORD ((crypt_word_t)(MAX_CRYPT_UWORD >> 1))
32 #define MIN_CRYPT_WORD (~MAX_CRYPT_WORD)
33 #define LARGEST_NUMBER (MAX((ALG_RSA * MAX_RSA_KEY_BYTES), \
34 MAX((ALG_ECC * MAX_ECC_KEY_BYTES), MAX_DIGEST_SIZE)))
35 #define LARGEST_NUMBER_BITS (LARGEST_NUMBER * 8)
36 #define MAX_ECC_PARAMETER_BYTES (MAX_ECC_KEY_BYTES * ALG_ECC)
These are the basic big number formats. This is convertible to the library- specific format without to much
difficulty. For the math performed using these numbers, the value is always positive.
Some things that are done often. Test to see if a bignum_t is equal to zero
Determine if a BIGNUM is even. A zero is even. Although the indication that a number is zero is that it's
size is zero, all words of the number are 0 so this test works on zero.
The macros below are used to define BIGNUM values of the required size. The values are allocated on
the stack so they can be treated like simple local values. This will call the initialization function for a
defined bignum_t. This sets the allocated and used fields and clears the words of n.
59 #define BN_INIT(name) \
60 (bigNum)BnInit((bigNum)&(name), \
61 BYTES_TO_CRYPT_WORDS(sizeof(name.d)))
In some cases, a function will need the address of the structure associated with a variable. The structure
for a BIGNUM variable of name is name_. Generally, when the structure is created, it is initialized and a
parameter is created with a pointer to the structure. The pointer has the name and the structure it points
to is name_
64 #define BN_STRUCT(bits) \
65 BN_STRUCT_DEF(BN_STRUCT_ALLOCATION(bits))
This creates a local BIGNUM variable of a specific size and initializes it from a TPM2B input parameter.
Create a type that can hold the largest number defined by the implementation.
This is used to created a word-size BIGNUM and initialize it with an input parameter to a function.
ECC-Specific Values This is the format for a point. It is always in affine format. The Z value is carried as
part of the point, primarily to simplify the interface to the support library. Rather than have the interface
layer have to create space for the point each time it is used... The x, y, and z values are pointers to
bigNum values and not in-line versions of the numbers. This is a relic of the days when there was no
standard TPM format for the numbers
98 BN_TYPE(ecc, ECC_BITS);
99 #define ECC_NUM(name) BN_VAR(name, ECC_BITS)
100 #define ECC_INITIALIZED(name, initializer) \
101 BN_INITIALIZED(name, ECC_BITS, initializer)
102 #define POINT_INSTANCE(name, bits) \
103 BN_STRUCT (bits) name##_x = \
104 {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \
105 BN_STRUCT ( bits ) name##_y = \
106 {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \
107 BN_STRUCT ( bits ) name##_z = \
108 {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \
109 bn_point_t name##_
110 #define POINT_INITIALIZER(name) \
111 BnInitializePoint(&name##_, (bigNum)&name##_x, \
112 (bigNum)&name##_y, (bigNum)&name##_z)
113 #define POINT_INITIALIZED(name, initValue) \
114 POINT_INSTANCE(name, MAX_ECC_KEY_BITS); \
115 bigPoint name = BnPointFrom2B( \
116 POINT_INITIALIZER(name), \
117 initValue)
118 #define POINT_VAR(name, bits) \
119 POINT_INSTANCE (name, bits); \
120 bigPoint name = POINT_INITIALIZER(name)
121 #define POINT(name) POINT_VAR(name, MAX_ECC_KEY_BITS)
Access macros for the ECC_CURVE structure. The parameter C is a pointer to an ECC_CURVE_DATA
structure. In some libraries, the curve structure contains a pointer to an ECC_CURVE_DATA structure as
well as some other bits. For those cases, the AccessCurveData() macro is used in the code to first get the
pointer to the ECC_CURVE_DATA for access. In some cases, the macro does noting.
Convert bytes in initializers according to the endianess of the system. This is used for CryptEccData.c.
Add implementation dependent definitions for other ECC Values and for linkages.
10.1.2 CryptEcc.h
10.1.2.1 Introduction
This file contains structure definitions used for ECC. The structures in this file are only used internally.
The ECC-related structures that cross the TPM interface are defined in TpmTypes.h
1 #ifndef _CRYPT_ECC_H
2 #define _CRYPT_ECC_H
10.1.2.2 Structures
This is used to define the macro that may or may not be in the data set for the curve (CryptEccData.c). If
there is a mismatch, the compiler will warn that there is to much/not enough initialization data in the
curve. The macro is used because not all versions of the CryptEccData.c need the curve name.
3 #ifdef NAMED_CURVES
4 #define CURVE_NAME(a) , a
5 #define CURVE_NAME_DEF const char *name;
6 #else
7 # define CURVE_NAME(a)
8 # define CURVE_NAME_DEF
9 #endif
10 typedef struct ECC_CURVE
11 {
12 const TPM_ECC_CURVE curveId;
13 const UINT16 keySizeBits;
14 const TPMT_KDF_SCHEME kdf;
15 const TPMT_ECC_SCHEME sign;
16 const ECC_CURVE_DATA *curveData; // the address of the curve data
17 const BYTE *OID;
18 CURVE_NAME_DEF
19 } ECC_CURVE;
20 extern const ECC_CURVE eccCurves[ECC_CURVE_COUNT];
21
22 #endif
10.1.3 CryptHash.h
10.1.3.1 Introduction
This header contains the hash structure definitions used in the TPM code to define the amount of space
to be reserved for the hash state. This allows the TPM code to not have to import all of the symbols used
by the hash computations. This lets the build environment of the TPM code not to have include the
header files associated with the CryptoEngine() code.
1 #ifndef _CRYPT_HASH_H
2 #define _CRYPT_HASH_H
3 union SMAC_STATES;
These definitions add the high-level methods for processing state that may be an SMAC
These definitions are here because the SMAC state is in the union of hash states.
44 #if ALG_SHA384
45 tpmHashStateSHA384_t Sha384;
46 #endif
47 #if ALG_SHA512
48 tpmHashStateSHA512_t Sha512;
49 #endif
50 #if ALG_SM3_256
51 tpmHashStateSM3_256_t Sm3_256;
52 #endif
53
54 // Additions for symmetric block cipher MAC
55 #if SMAC_IMPLEMENTED
56 SMAC_STATE smac;
57 #endif
58 // to force structure alignment to be no worse than HASH_ALIGNMENT
59 #if HASH_ALIGNMENT == 4
60 uint32_t align;
61 #else
62 uint64_t align;
63 #endif
64 } ANY_HASH_STATE;
65 typedef ANY_HASH_STATE *PANY_HASH_STATE;
66 typedef const ANY_HASH_STATE *PCANY_HASH_STATE;
67 #define ALIGNED_SIZE(x, b) ((((x) + (b) - 1) / (b)) * (b))
MAX_HASH_STATE_SIZE will change with each implementation. It is assumed that a hash state will not
be larger than twice the block size plus some overhead (in this case, 16 bytes). The overall size needs to
be as large as any of the hash contexts. The structure needs to start on an alignment boundary and be an
even multiple of the alignment
This is an aligned byte array that will hold any of the hash contexts.
The header associated with the hash library is expected to define the methods which include the calling
sequence. When not compiling CryptHash.c, the methods are not defined so we need placeholder
functions for the structures
72 #ifndef HASH_START_METHOD_DEF
73 # define HASH_START_METHOD_DEF void (HASH_START_METHOD)(void)
74 #endif
75 #ifndef HASH_DATA_METHOD_DEF
76 # define HASH_DATA_METHOD_DEF void (HASH_DATA_METHOD)(void)
77 #endif
78 #ifndef HASH_END_METHOD_DEF
79 # define HASH_END_METHOD_DEF void (HASH_END_METHOD)(void)
80 #endif
81 #ifndef HASH_STATE_COPY_METHOD_DEF
82 # define HASH_STATE_COPY_METHOD_DEF void (HASH_STATE_COPY_METHOD)(void)
83 #endif
84 #ifndef HASH_STATE_EXPORT_METHOD_DEF
85 # define HASH_STATE_EXPORT_METHOD_DEF void (HASH_STATE_EXPORT_METHOD)(void)
86 #endif
87 #ifndef HASH_STATE_IMPORT_METHOD_DEF
88 # define HASH_STATE_IMPORT_METHOD_DEF void (HASH_STATE_IMPORT_METHOD)(void)
89 #endif
Define the prototypical function call for each of the methods. This defines the order in which the
parameters are passed to the underlying function.
90 typedef HASH_START_METHOD_DEF;
91 typedef HASH_DATA_METHOD_DEF;
92 typedef HASH_END_METHOD_DEF;
93 typedef HASH_STATE_COPY_METHOD_DEF;
94 typedef HASH_STATE_EXPORT_METHOD_DEF;
95 typedef HASH_STATE_IMPORT_METHOD_DEF;
96 typedef struct _HASH_METHODS
97 {
98 HASH_START_METHOD *start;
99 HASH_DATA_METHOD *data;
100 HASH_END_METHOD *end;
101 HASH_STATE_COPY_METHOD *copy; // Copy a hash block
102 HASH_STATE_EXPORT_METHOD *copyOut; // Copy a hash block from a hash
103 // context
104 HASH_STATE_IMPORT_METHOD *copyIn; // Copy a hash block to a proper hash
105 // context
106 } HASH_METHODS, *PHASH_METHODS;
107 #if ALG_SHA1
108 TPM2B_TYPE(SHA1_DIGEST, SHA1_DIGEST_SIZE);
109 #endif
110 #if ALG_SHA256
111 TPM2B_TYPE(SHA256_DIGEST, SHA256_DIGEST_SIZE);
112 #endif
113 #if ALG_SHA384
114 TPM2B_TYPE(SHA384_DIGEST, SHA384_DIGEST_SIZE);
115 #endif
116 #if ALG_SHA512
117 TPM2B_TYPE(SHA512_DIGEST, SHA512_DIGEST_SIZE);
118 #endif
119 #if ALG_SM3_256
120 TPM2B_TYPE(SM3_256_DIGEST, SM3_256_DIGEST_SIZE);
121 #endif
When the TPM implements RSA, the hash-dependent OID pointers are part of the HASH_DEF. These
macros conditionally add the OID reference to the HASH_DEF and the HASH_DEF_TEMPLATE.
When the TPM implements ECC, the hash-dependent OID pointers are part of the HASH_DEF. These
macros conditionally add the OID reference to the HASH_DEF and the HASH_DEF_TEMPLATE.
Macro to fill in the HASH_DEF for an algorithm. For SHA1, the instance would be:
HASH_DEF_TEMPLATE(Sha1, SHA1) This handles the difference in capitalization for the various pieces.
These definitions are for the types that can be in a hash state structure. These types are used in the
cryptographic utilities. This is a define rather than an enum so that the size of this field can be explicit.
This is the structure that is used for passing a context into the hashing functions. It should be the same
size as the function context used within the hashing functions. This is checked when the hash function is
initialized. This version uses a new layout for the contexts and a different definition. The state buffer is an
array of HASH_UNIT values so that a decent compiler will put the structure on a HASH_UNIT boundary.
If the structure is not properly aligned, the code that manipulates the structure will copy to a properly
aligned structure before it is used and copy the result back. This just makes things slower.
NOTE: This version of the state had the pointer to the update method in the state. This is to allow the SMAC functions
to use the same structure without having to replicate the entire HASH_DEF structure.
An HMAC_STATE structure contains an opaque HMAC stack state. A caller would use this structure
when performing incremental HMAC operations. This structure contains a hash state and an HMAC key
and allows slightly better stack optimization than adding an HMAC key to each hash state.
This is for the external hash state. This implementation assumes that the size of the exported hash state
is no larger than the internal hash state.
10.1.4 CryptRand.h
10.1.4.1 Introduction
This file contains constant definition shared by CryptUtil() and the parts of the Crypto Engine.
1 #ifndef _CRYPT_RAND_H
2 #define _CRYPT_RAND_H
Values and structures for the random number generator. These values are defined in this header file so
that the size of the RNG state can be known to TPM.lib. This allows the allocation of some space in NV
memory for the state to be stored on an orderly shutdown. The DRBG based on a symmetric block cipher
is defined by three values,
the key size
the block size (the IV size)
the symmetric algorithm
Derived values
40 BYTE bytes[DRBG_SEED_SIZE_BYTES];
41 crypt_uword_t words[DRBG_SEED_SIZE_WORDS];
42 } DRBG_SEED;
43 #define CTR_DRBG_MAX_REQUESTS_PER_RESEED ((UINT64)1 << 20)
44 #define CTR_DRBG_MAX_BYTES_PER_REQUEST (1 << 16)
45 # define CTR_DRBG_MIN_ENTROPY_INPUT_LENGTH DRBG_SEED_SIZE_BYTES
46 # define CTR_DRBG_MAX_ENTROPY_INPUT_LENGTH DRBG_SEED_SIZE_BYTES
47 # define CTR_DRBG_MAX_ADDITIONAL_INPUT_LENGTH DRBG_SEED_SIZE_BYTES
48 #define TESTING (1 << 0)
49 #define ENTROPY (1 << 1)
50 #define TESTED (1 << 2)
51 #define IsTestStateSet(BIT) ((g_cryptoSelfTestState.rng & BIT) != 0)
52 #define SetTestStateBit(BIT) (g_cryptoSelfTestState.rng |= BIT)
53 #define ClearTestStateBit(BIT) (g_cryptoSelfTestState.rng &= ~BIT)
54 #define IsSelfTest() IsTestStateSet(TESTING)
55 #define SetSelfTest() SetTestStateBit(TESTING)
56 #define ClearSelfTest() ClearTestStateBit(TESTING)
57 #define IsEntropyBad() IsTestStateSet(ENTROPY)
58 #define SetEntropyBad() SetTestStateBit(ENTROPY)
59 #define ClearEntropyBad() ClearTestStateBit(ENTROPY)
60 #define IsDrbgTested() IsTestStateSet(TESTED)
61 #define SetDrbgTested() SetTestStateBit(TESTED)
62 #define ClearDrbgTested() ClearTestStateBit(TESTED)
63 typedef struct
64 {
65 UINT64 reseedCounter;
66 UINT32 magic;
67 DRBG_SEED seed; // contains the key and IV for the counter mode DRBG
68 UINT32 lastValue[4]; // used when the TPM does continuous self-test
69 // for FIPS compliance of DRBG
70 } DRBG_STATE, *pDRBG_STATE;
71 #define DRBG_MAGIC ((UINT32) 0x47425244) // "DRBG" backwards so that it displays
72 typedef struct
73 {
74 UINT64 counter;
75 UINT32 magic;
76 UINT32 limit;
77 TPM2B *seed;
78 const TPM2B *label;
79 TPM2B *context;
80 TPM_ALG_ID hash;
81 TPM_ALG_ID kdf;
82 UINT16 digestSize;
83 TPM2B_DIGEST residual;
84 } KDF_STATE, *pKDR_STATE;
85 #define KDF_MAGIC ((UINT32) 0x4048444a) // "KDF " backwards
Make sure that any other structures added to this union start with a 64-bit counter and a 32-bit magic
number
86 typedef union
87 {
88 DRBG_STATE drbg;
89 KDF_STATE kdf;
90 } RAND_STATE;
This is the state used when the library uses a random number generator. A special function is installed for
the library to call. That function picks up the state from this location and uses it for the generation of the
random number.
10.1.5 CryptRsa.h
1 #ifndef _CRYPT_RSA_H
2 #define _CRYPT_RSA_H
These values are used in the bigNum representation of various RSA values.
3 BN_TYPE(rsa, MAX_RSA_KEY_BITS);
4 #define BN_RSA(name) BN_VAR(name, MAX_RSA_KEY_BITS)
5 #define BN_RSA_INITIALIZED(name, initializer) \
6 BN_INITIALIZED(name, MAX_RSA_KEY_BITS, initializer)
7 #define BN_PRIME(name) BN_VAR(name, (MAX_RSA_KEY_BITS / 2))
8 BN_TYPE(prime, (MAX_RSA_KEY_BITS / 2));
9 #define BN_PRIME_INITIALIZED(name, initializer) \
10 BN_INITIALIZED(name, MAX_RSA_KEY_BITS / 2, initializer)
11 #if !CRT_FORMAT_RSA
12 # error This verson only works with CRT formatted data
13 #endif // !CRT_FORMAT_RSA
14 typedef struct privateExponent
15 {
16 bigNum P;
17 bigNum Q;
18 bigNum dP;
19 bigNum dQ;
20 bigNum qInv;
21 bn_prime_t entries[5];
22 } privateExponent;
23 #define NEW_PRIVATE_EXPONENT(X) \
24 privateExponent _##X; \
25 privateExponent *X = RsaInitializeExponent(&(_##X))
26 #endif // _CRYPT_RSA_H
10.1.6 CryptTest.h
1 #ifndef _CRYPT_TEST_H
2 #define _CRYPT_TEST_H
This is the definition of a bit array with one bit per algorithm.
NOTE: Since bit numbering starts at zero, when ALG_LAST_VALUE is a multiple of 8, ALGORITHM_VECTOR will
need to have byte for the single bit in the last byte. So, for example, when ALG_LAST_VECTOR is 8,
ALGORITHM_VECTOR will need 2 bytes.
10.1.7 HashTestData.h
59 TPM2B_TYPE(SHA512, 64);
60 TPM2B_SHA512 c_SHA512_digest = {{64, {
61 0xe2,0x7b,0x10,0x3d,0x5e,0x48,0x58,0x44,0x67,0xac,0xa3,0x81,0x8c,0x1d,0xc5,0x71,
62 0x66,0x92,0x8a,0x89,0xaa,0xd4,0x35,0x51,0x60,0x37,0x31,0xd7,0xba,0xe7,0x93,0x0b,
63 0x16,0x4d,0xb3,0xc8,0x34,0x98,0x3c,0xd3,0x53,0xde,0x5e,0xe8,0x0c,0xbc,0xaf,0xc9,
64 0x24,0x2c,0xcc,0xed,0xdb,0xde,0xba,0x1f,0x14,0x14,0x5a,0x95,0x80,0xde,0x66,0xbd
65 }}};
66 #endif
10.1.8 KdfTestData.h
1 #define TEST_KDF_KEY_SIZE 20
2 TPM2B_TYPE(KDF_TEST_KEY, TEST_KDF_KEY_SIZE);
3 TPM2B_KDF_TEST_KEY c_kdfTestKeyIn = {{TEST_KDF_KEY_SIZE, {
4 0x27, 0x1F, 0xA0, 0x8B, 0xBD, 0xC5, 0x06, 0x0E, 0xC3, 0xDF,
5 0xA9, 0x28, 0xFF, 0x9B, 0x73, 0x12, 0x3A, 0x12, 0xDA, 0x0C }}};
6
7 TPM2B_TYPE(KDF_TEST_LABEL, 17);
8 TPM2B_KDF_TEST_LABEL c_kdfTestLabel = {{17, {
9 0x4B, 0x44, 0x46, 0x53, 0x45, 0x4C, 0x46, 0x54,
10 0x45, 0x53, 0x54, 0x4C, 0x41, 0x42, 0x45, 0x4C, 0x00 }}};
11
12 TPM2B_TYPE(KDF_TEST_CONTEXT, 8);
13 TPM2B_KDF_TEST_CONTEXT c_kdfTestContextU = {{8, {
14 0xCE, 0x24, 0x4F, 0x39, 0x5D, 0xCA, 0x73, 0x91 }}};
15
16 TPM2B_KDF_TEST_CONTEXT c_kdfTestContextV = {{8, {
17 0xDA, 0x50, 0x40, 0x31, 0xDD, 0xF1, 0x2E, 0x83 }}};
18
19 #if ALG_SHA512 == ALG_YES
20 TPM2B_KDF_TEST_KEY c_kdfTestKeyOut = {{20, {
21 0x8b, 0xe2, 0xc1, 0xb8, 0x5b, 0x78, 0x56, 0x9b, 0x9f, 0xa7,
22 0x59, 0xf5, 0x85, 0x7c, 0x56, 0xd6, 0x84, 0x81, 0x0f, 0xd3 }}};
23 #define KDF_TEST_ALG TPM_ALG_SHA512
24
25 #elif ALG_SHA384 == ALG_YES
26 TPM2B_KDF_TEST_KEY c_kdfTestKeyOut = {{20, {
27 0x1d, 0xce, 0x70, 0xc9, 0x11, 0x3e, 0xb2, 0xdb, 0xa4, 0x7b,
28 0xd9, 0xcf, 0xc7, 0x2b, 0xf4, 0x6f, 0x45, 0xb0, 0x93, 0x12 }}};
29 #define KDF_TEST_ALG TPM_ALG_SHA384
30
31 #elif ALG_SHA256 == ALG_YES
32 TPM2B_KDF_TEST_KEY c_kdfTestKeyOut = {{20, {
33 0xbb, 0x02, 0x59, 0xe1, 0xc8, 0xba, 0x60, 0x7e, 0x6a, 0x2c,
34 0xd7, 0x04, 0xb6, 0x9a, 0x90, 0x2e, 0x9a, 0xde, 0x84, 0xc4 }}};
35 #define KDF_TEST_ALG TPM_ALG_SHA256
36
37 #elif ALG_SHA1 == ALG_YES
38 TPM2B_KDF_TEST_KEY c_kdfTestKeyOut = {{20, {
39 0x55, 0xb5, 0xa7, 0x18, 0x4a, 0xa0, 0x74, 0x23, 0xc4, 0x7d,
40 0xae, 0x76, 0x6c, 0x26, 0xa2, 0x37, 0x7d, 0x7c, 0xf8, 0x51 }}};
41 #define KDF_TEST_ALG TPM_ALG_SHA1
42 #endif
10.1.9 RsaTestData.h
57
0x6e,0x20,0xf5,0xcb,0xca,0x47,0xf2,0x17,0xaa,0x8b,0xbc,0x13,0x14,0x84,0xf6,0xab};
58
59 const TPM2B_RSA_TEST_VALUE c_RsaepKvt = {RSA_TEST_KEY_SIZE, {
60 0x73,0xbd,0x65,0x49,0xda,0x7b,0xb8,0x50,0x9e,0x87,0xf0,0x0a,0x8a,0x9a,0x07,0xb6,
61 0x00,0x82,0x10,0x14,0x60,0xd8,0x01,0xfc,0xc5,0x18,0xea,0x49,0x5f,0x13,0xcf,0x65,
62 0x66,0x30,0x6c,0x60,0x3f,0x24,0x3c,0xfb,0xe2,0x31,0x16,0x99,0x7e,0x31,0x98,0xab,
63 0x93,0xb8,0x07,0x53,0xcc,0xdb,0x7f,0x44,0xd9,0xee,0x5d,0xe8,0x5f,0x97,0x5f,0xe8,
64 0x1f,0x88,0x52,0x24,0x7b,0xac,0x62,0x95,0xb7,0x7d,0xf5,0xf8,0x9f,0x5a,0xa8,0x24,
65 0x9a,0x76,0x71,0x2a,0x35,0x2a,0xa1,0x08,0xbb,0x95,0xe3,0x64,0xdc,0xdb,0xc2,0x33,
66 0xa9,0x5f,0xbe,0x4c,0xc4,0xcc,0x28,0xc9,0x25,0xff,0xee,0x17,0x15,0x9a,0x50,0x90,
67 0x0e,0x15,0xb4,0xea,0x6a,0x09,0xe6,0xff,0xa4,0xee,0xc7,0x7e,0xce,0xa9,0x73,0xe4,
68 0xa0,0x56,0xbd,0x53,0x2a,0xe4,0xc0,0x2b,0xa8,0x9b,0x09,0x30,0x72,0x62,0x0f,0xf9,
69 0xf6,0xa1,0x52,0xd2,0x8a,0x37,0xee,0xa5,0xc8,0x47,0xe1,0x99,0x21,0x47,0xeb,0xdd,
70 0x37,0xaa,0xe4,0xbd,0x55,0x46,0x5a,0x5a,0x5d,0xfb,0x7b,0xfc,0xff,0xbf,0x26,0x71,
71 0xf6,0x1e,0xad,0xbc,0xbf,0x33,0xca,0xe1,0x92,0x8f,0x2a,0x89,0x6c,0x45,0x24,0xd1,
72 0xa6,0x52,0x56,0x24,0x5e,0x90,0x47,0xe5,0xcb,0x12,0xb0,0x32,0xf9,0xa6,0xbb,0xea,
73 0x37,0xa9,0xbd,0xef,0x23,0xef,0x63,0x07,0x6c,0xc4,0x4e,0x64,0x3c,0xc6,0x11,0x84,
74 0x7d,0x65,0xd6,0x5d,0x7a,0x17,0x58,0xa5,0xf7,0x74,0x3b,0x42,0xe3,0xd2,0xda,0x5f,
75
0x6f,0xe0,0x1e,0x4b,0xcf,0x46,0xe2,0xdf,0x3e,0x41,0x8e,0x0e,0xb0,0x3f,0x8b,0x65}};
76
77 #define OAEP_TEST_LABEL "OAEP Test Value"
78
79 #if ALG_SHA1_VALUE == DEFAULT_TEST_HASH
80
81 const TPM2B_RSA_TEST_VALUE c_OaepKvt = {RSA_TEST_KEY_SIZE, {
82 0x32,0x68,0x84,0x0b,0x9c,0xc9,0x25,0x26,0xd9,0xc0,0xd0,0xb1,0xde,0x60,0x55,0xae,
83 0x33,0xe5,0xcf,0x6c,0x85,0xbe,0x0d,0x71,0x11,0xe1,0x45,0x60,0xbb,0x42,0x3d,0xf3,
84 0xb1,0x18,0x84,0x7b,0xc6,0x5d,0xce,0x1d,0x5f,0x9a,0x97,0xcf,0xb1,0x97,0x9a,0x85,
85 0x7c,0xa7,0xa1,0x63,0x23,0xb6,0x74,0x0f,0x1a,0xee,0x29,0x51,0xeb,0x50,0x8f,0x3c,
86 0x8e,0x4e,0x31,0x38,0xdc,0x11,0xfc,0x9a,0x4e,0xaf,0x93,0xc9,0x7f,0x6e,0x35,0xf3,
87 0xc9,0xe4,0x89,0x14,0x53,0xe2,0xc2,0x1a,0xf7,0x6b,0x9b,0xf0,0x7a,0xa4,0x69,0x52,
88 0xe0,0x24,0x8f,0xea,0x31,0xa7,0x5c,0x43,0xb0,0x65,0xc9,0xfe,0xba,0xfe,0x80,0x9e,
89 0xa5,0xc0,0xf5,0x8d,0xce,0x41,0xf9,0x83,0x0d,0x8e,0x0f,0xef,0x3d,0x1f,0x6a,0xcc,
90 0x8a,0x3d,0x3b,0xdf,0x22,0x38,0xd7,0x34,0x58,0x7b,0x55,0xc9,0xf6,0xbc,0x7c,0x4c,
91 0x3f,0xd7,0xde,0x4e,0x30,0xa9,0x69,0xf3,0x5f,0x56,0x8f,0xc2,0xe7,0x75,0x79,0xb8,
92 0xa5,0xc8,0x0d,0xc0,0xcd,0xb6,0xc9,0x63,0xad,0x7c,0xe4,0x8f,0x39,0x60,0x4d,0x7d,
93 0xdb,0x34,0x49,0x2a,0x47,0xde,0xc0,0x42,0x4a,0x19,0x94,0x2e,0x50,0x21,0x03,0x47,
94 0xff,0x73,0xb3,0xb7,0x89,0xcc,0x7b,0x2c,0xeb,0x03,0xa7,0x9a,0x06,0xfd,0xed,0x19,
95 0xbb,0x82,0xa0,0x13,0xe9,0xfa,0xac,0x06,0x5f,0xc5,0xa9,0x2b,0xda,0x88,0x23,0xa2,
96 0x5d,0xc2,0x7f,0xda,0xc8,0x5a,0x94,0x31,0xc1,0x21,0xd7,0x1e,0x6b,0xd7,0x89,0xb1,
97
0x93,0x80,0xab,0xd1,0x37,0xf2,0x6f,0x50,0xcd,0x2a,0xea,0xb1,0xc4,0xcd,0xcb,0xb5}};
98
99 const TPM2B_RSA_TEST_VALUE c_RsaesKvt = {RSA_TEST_KEY_SIZE, {
100 0x29,0xa4,0x2f,0xbb,0x8a,0x14,0x05,0x1e,0x3c,0x72,0x76,0x77,0x38,0xe7,0x73,0xe3,
101 0x6e,0x24,0x4b,0x38,0xd2,0x1a,0xcf,0x23,0x58,0x78,0x36,0x82,0x23,0x6e,0x6b,0xef,
102 0x2c,0x3d,0xf2,0xe8,0xd6,0xc6,0x87,0x8e,0x78,0x9b,0x27,0x39,0xc0,0xd6,0xef,0x4d,
103 0x0b,0xfc,0x51,0x27,0x18,0xf3,0x51,0x5e,0x4d,0x96,0x3a,0xe2,0x15,0xe2,0x7e,0x42,
104 0xf4,0x16,0xd5,0xc6,0x52,0x5d,0x17,0x44,0x76,0x09,0x7a,0xcf,0xe3,0x30,0xe3,0x84,
105 0xf6,0x6f,0x3a,0x33,0xfb,0x32,0x0d,0x1d,0xe7,0x7c,0x80,0x82,0x4f,0xed,0xda,0x87,
106 0x11,0x9c,0xc3,0x7e,0x85,0xbd,0x18,0x58,0x08,0x2b,0x23,0x37,0xe7,0x9d,0xd0,0xd1,
107 0x79,0xe2,0x05,0xbd,0xf5,0x4f,0x0e,0x0f,0xdb,0x4a,0x74,0xeb,0x09,0x01,0xb3,0xca,
108 0xbd,0xa6,0x7b,0x09,0xb1,0x13,0x77,0x30,0x4d,0x87,0x41,0x06,0x57,0x2e,0x5f,0x36,
109 0x6e,0xfc,0x35,0x69,0xfe,0x0a,0x24,0x6c,0x98,0x8c,0xda,0x97,0xf4,0xfb,0xc7,0x83,
110 0x2d,0x3e,0x7d,0xc0,0x5c,0x34,0xfd,0x11,0x2a,0x12,0xa7,0xae,0x4a,0xde,0xc8,0x4e,
111 0xcf,0xf4,0x85,0x63,0x77,0xc6,0x33,0x34,0xe0,0x27,0xe4,0x9e,0x91,0x0b,0x4b,0x85,
112 0xf0,0xb0,0x79,0xaa,0x7c,0xc6,0xff,0x3b,0xbc,0x04,0x73,0xb8,0x95,0xd7,0x31,0x54,
113 0x3b,0x56,0xec,0x52,0x15,0xd7,0x3e,0x62,0xf5,0x82,0x99,0x3e,0x2a,0xc0,0x4b,0x2e,
114 0x06,0x57,0x6d,0x3f,0x3e,0x77,0x1f,0x2b,0x2d,0xc5,0xb9,0x3b,0x68,0x56,0x73,0x70,
115
0x32,0x6b,0x6b,0x65,0x25,0x76,0x45,0x6c,0x45,0xf1,0x6c,0x59,0xfc,0x94,0xa7,0x15}};
116
117 const TPM2B_RSA_TEST_VALUE c_RsapssKvt = {RSA_TEST_KEY_SIZE, {
118 0x01,0xfe,0xd5,0x83,0x0b,0x15,0xba,0x90,0x2c,0xdf,0xf7,0x26,0xb7,0x8f,0xb1,0xd7,
119 0x0b,0xfd,0x83,0xf9,0x95,0xd5,0xd7,0xb5,0xc5,0xc5,0x4a,0xde,0xd5,0xe6,0x20,0x78,
120 0xca,0x73,0x77,0x3d,0x61,0x36,0x48,0xae,0x3e,0x8f,0xee,0x43,0x29,0x96,0xdf,0x3f,
121 0x1c,0x97,0x5a,0xbe,0xe5,0xa2,0x7e,0x5b,0xd0,0xc0,0x29,0x39,0x83,0x81,0x77,0x24,
122 0x43,0xdb,0x3c,0x64,0x4d,0xf0,0x23,0xe4,0xae,0x0f,0x78,0x31,0x8c,0xda,0x0c,0xec,
123 0xf1,0xdf,0x09,0xf2,0x14,0x6a,0x4d,0xaf,0x36,0x81,0x6e,0xbd,0xbe,0x36,0x79,0x88,
124 0x98,0xb6,0x6f,0x5a,0xad,0xcf,0x7c,0xee,0xe0,0xdd,0x00,0xbe,0x59,0x97,0x88,0x00,
125 0x34,0xc0,0x8b,0x48,0x42,0x05,0x04,0x5a,0xb7,0x85,0x38,0xa0,0x35,0xd7,0x3b,0x51,
126 0xb8,0x7b,0x81,0x83,0xee,0xff,0x76,0x6f,0x50,0x39,0x4d,0xab,0x89,0x63,0x07,0x6d,
127 0xf5,0xe5,0x01,0x10,0x56,0xfe,0x93,0x06,0x8f,0xd3,0xc9,0x41,0xab,0xc9,0xdf,0x6e,
128 0x59,0xa8,0xc3,0x1d,0xbf,0x96,0x4a,0x59,0x80,0x3c,0x90,0x3a,0x59,0x56,0x4c,0x6d,
129 0x44,0x6d,0xeb,0xdc,0x73,0xcd,0xc1,0xec,0xb8,0x41,0xbf,0x89,0x8c,0x03,0x69,0x4c,
130 0xaf,0x3f,0xc1,0xc5,0xc7,0xe7,0x7d,0xa7,0x83,0x39,0x70,0xa2,0x6b,0x83,0xbc,0xbe,
131 0xf5,0xbf,0x1c,0xee,0x6e,0xa3,0x22,0x1e,0x25,0x2f,0x16,0x68,0x69,0x5a,0x1d,0xfa,
132 0x2c,0x3a,0x0f,0x67,0xe1,0x77,0x12,0xe8,0x3d,0xba,0xaa,0xef,0x96,0x9c,0x1f,0x64,
133
0x32,0xf4,0xa7,0xb3,0x3f,0x7d,0x61,0xbb,0x9a,0x27,0xad,0xfb,0x2f,0x33,0xc4,0x70}};
134
135 const TPM2B_RSA_TEST_VALUE c_RsassaKvt = {RSA_TEST_KEY_SIZE, {
136 0x67,0x4e,0xdd,0xc2,0xd2,0x6d,0xe0,0x03,0xc4,0xc2,0x41,0xd3,0xd4,0x61,0x30,0xd0,
137 0xe1,0x68,0x31,0x4a,0xda,0xd9,0xc2,0x5d,0xaa,0xa2,0x7b,0xfb,0x44,0x02,0xf5,0xd6,
138 0xd8,0x2e,0xcd,0x13,0x36,0xc9,0x4b,0xdb,0x1a,0x4b,0x66,0x1b,0x4f,0x9c,0xb7,0x17,
139 0xac,0x53,0x37,0x4f,0x21,0xbd,0x0c,0x66,0xac,0x06,0x65,0x52,0x9f,0x04,0xf6,0xa5,
140 0x22,0x5b,0xf7,0xe6,0x0d,0x3c,0x9f,0x41,0x19,0x09,0x88,0x7c,0x41,0x4c,0x2f,0x9c,
141 0x8b,0x3c,0xdd,0x7c,0x28,0x78,0x24,0xd2,0x09,0xa6,0x5b,0xf7,0x3c,0x88,0x7e,0x73,
142 0x5a,0x2d,0x36,0x02,0x4f,0x65,0xb0,0xcb,0xc8,0xdc,0xac,0xa2,0xda,0x8b,0x84,0x91,
143 0x71,0xe4,0x30,0x8b,0xb6,0x12,0xf2,0xf0,0xd0,0xa0,0x38,0xcf,0x75,0xb7,0x20,0xcb,
144 0x35,0x51,0x52,0x6b,0xc4,0xf4,0x21,0x95,0xc2,0xf7,0x9a,0x13,0xc1,0x1a,0x7b,0x8f,
145 0x77,0xda,0x19,0x48,0xbb,0x6d,0x14,0x5d,0xba,0x65,0xb4,0x9e,0x43,0x42,0x58,0x98,
146 0x0b,0x91,0x46,0xd8,0x4c,0xf3,0x4c,0xaf,0x2e,0x02,0xa6,0xb2,0x49,0x12,0x62,0x43,
147 0x4e,0xa8,0xac,0xbf,0xfd,0xfa,0x37,0x24,0xea,0x69,0x1c,0xf5,0xae,0xfa,0x08,0x82,
148 0x30,0xc3,0xc0,0xf8,0x9a,0x89,0x33,0xe1,0x40,0x6d,0x18,0x5c,0x7b,0x90,0x48,0xbf,
149 0x37,0xdb,0xea,0xfb,0x0e,0xd4,0x2e,0x11,0xfa,0xa9,0x86,0xff,0x00,0x0b,0x7b,0xca,
150 0x09,0x64,0x6a,0x8f,0x0c,0x0e,0x09,0x14,0x36,0x4a,0x74,0x31,0x18,0x5b,0x18,0xeb,
151
0xea,0x83,0xc3,0x66,0x68,0xa6,0x7d,0x43,0x06,0x0f,0x99,0x60,0xce,0x65,0x08,0xf6}};
152
153 #endif // SHA1
154
155 #if ALG_SHA256_VALUE == DEFAULT_TEST_HASH
156
157 const TPM2B_RSA_TEST_VALUE c_OaepKvt = {RSA_TEST_KEY_SIZE, {
158 0x33,0x20,0x6e,0x21,0xc3,0xf6,0xcd,0xf8,0xd7,0x5d,0x9f,0xe9,0x05,0x14,0x8c,0x7c,
159 0xbb,0x69,0x24,0x9e,0x52,0x8f,0xaf,0x84,0x73,0x21,0x2c,0x85,0xa5,0x30,0x4d,0xb6,
160 0xb8,0xfa,0x15,0x9b,0xc7,0x8f,0xc9,0x7a,0x72,0x4b,0x85,0xa4,0x1c,0xc5,0xd8,0xe4,
161 0x92,0xb3,0xec,0xd9,0xa8,0xca,0x5e,0x74,0x73,0x89,0x7f,0xb4,0xac,0x7e,0x68,0x12,
162 0xb2,0x53,0x27,0x4b,0xbf,0xd0,0x71,0x69,0x46,0x9f,0xef,0xf4,0x70,0x60,0xf8,0xd7,
163 0xae,0xc7,0x5a,0x27,0x38,0x25,0x2d,0x25,0xab,0x96,0x56,0x66,0x3a,0x23,0x40,0xa8,
164 0xdb,0xbc,0x86,0xe8,0xf3,0xd2,0x58,0x0b,0x44,0xfc,0x94,0x1e,0xb7,0x5d,0xb4,0x57,
165 0xb5,0xf3,0x56,0xee,0x9b,0xcf,0x97,0x91,0x29,0x36,0xe3,0x06,0x13,0xa2,0xea,0xd6,
166 0xd6,0x0b,0x86,0x0b,0x1a,0x27,0xe6,0x22,0xc4,0x7b,0xff,0xde,0x0f,0xbf,0x79,0xc8,
167 0x1b,0xed,0xf1,0x27,0x62,0xb5,0x8b,0xf9,0xd9,0x76,0x90,0xf6,0xcc,0x83,0x0f,0xce,
168 0xce,0x2e,0x63,0x7a,0x9b,0xf4,0x48,0x5b,0xd7,0x81,0x2c,0x3a,0xdb,0x59,0x0d,0x4d,
169 0x9e,0x46,0xe9,0x9e,0x92,0x22,0x27,0x1c,0xb0,0x67,0x8a,0xe6,0x8a,0x16,0x8a,0xdf,
170 0x95,0x76,0x24,0x82,0xad,0xf1,0xbc,0x97,0xbf,0xd3,0x5e,0x6e,0x14,0x0c,0x5b,0x25,
171 0xfe,0x58,0xfa,0x64,0xe5,0x14,0x46,0xb7,0x58,0xc6,0x3f,0x7f,0x42,0xd2,0x8e,0x45,
172 0x13,0x41,0x85,0x12,0x2e,0x96,0x19,0xd0,0x5e,0x7d,0x34,0x06,0x32,0x2b,0xc8,0xd9,
173
0x0d,0x6c,0x06,0x36,0xa0,0xff,0x47,0x57,0x2c,0x25,0xbc,0x8a,0xa5,0xe2,0xc7,0xe3}};
174
175 const TPM2B_RSA_TEST_VALUE c_RsaesKvt = {RSA_TEST_KEY_SIZE, {
176 0x39,0xfc,0x10,0x5d,0xf4,0x45,0x3d,0x94,0x53,0x06,0x89,0x24,0xe7,0xe8,0xfd,0x03,
177 0xac,0xfd,0xbd,0xb2,0x28,0xd3,0x4a,0x52,0xc5,0xd4,0xdb,0x17,0xd4,0x24,0x05,0xc4,
178 0xeb,0x6a,0xce,0x1d,0xbb,0x37,0xcb,0x09,0xd8,0x6c,0x83,0x19,0x93,0xd4,0xe2,0x88,
179 0x88,0x9b,0xaf,0x92,0x16,0xc4,0x15,0xbd,0x49,0x13,0x22,0xb7,0x84,0xcf,0x23,0xf2,
180 0x6f,0x0c,0x3e,0x8f,0xde,0x04,0x09,0x31,0x2d,0x99,0xdf,0xe6,0x74,0x70,0x30,0xde,
181 0x8c,0xad,0x32,0x86,0xe2,0x7c,0x12,0x90,0x21,0xf3,0x86,0xb7,0xe2,0x64,0xca,0x98,
182 0xcc,0x64,0x4b,0xef,0x57,0x4f,0x5a,0x16,0x6e,0xd7,0x2f,0x5b,0xf6,0x07,0xad,0x33,
183 0xb4,0x8f,0x3b,0x3a,0x8b,0xd9,0x06,0x2b,0xed,0x3c,0x3c,0x76,0xf6,0x21,0x31,0xe3,
184 0xfb,0x2c,0x45,0x61,0x42,0xba,0xe0,0xc3,0x72,0x63,0xd0,0x6b,0x8f,0x36,0x26,0xfb,
185 0x9e,0x89,0x0e,0x44,0x9a,0xc1,0x84,0x5e,0x84,0x8d,0xb6,0xea,0xf1,0x0d,0x66,0xc7,
186 0xdb,0x44,0xbd,0x19,0x7c,0x05,0xbe,0xc4,0xab,0x88,0x32,0xbe,0xc7,0x63,0x31,0xe6,
187 0x38,0xd4,0xe5,0xb8,0x4b,0xf5,0x0e,0x55,0x9a,0x3a,0xe6,0x0a,0xec,0xee,0xe2,0xa8,
188 0x88,0x04,0xf2,0xb8,0xaa,0x5a,0xd8,0x97,0x5d,0xa0,0xa8,0x42,0xfb,0xd9,0xde,0x80,
189 0xae,0x4c,0xb3,0xa1,0x90,0x47,0x57,0x03,0x10,0x78,0xa6,0x8f,0x11,0xba,0x4b,0xce,
190 0x2d,0x56,0xa4,0xe1,0xbd,0xf8,0xa0,0xa4,0xd5,0x48,0x3c,0x63,0x20,0x00,0x38,0xa0,
191
0xd1,0xe6,0x12,0xe9,0x1d,0xd8,0x49,0xe3,0xd5,0x24,0xb5,0xc5,0x3a,0x1f,0xb0,0xd4}};
192
193 const TPM2B_RSA_TEST_VALUE c_RsapssKvt = {RSA_TEST_KEY_SIZE, {
194 0x74,0x89,0x29,0x3e,0x1b,0xac,0xc6,0x85,0xca,0xf0,0x63,0x43,0x30,0x7d,0x1c,0x9b,
195 0x2f,0xbd,0x4d,0x69,0x39,0x5e,0x85,0xe2,0xef,0x86,0x0a,0xc6,0x6b,0xa6,0x08,0x19,
196 0x6c,0x56,0x38,0x24,0x55,0x92,0x84,0x9b,0x1b,0x8b,0x04,0xcf,0x24,0x14,0x24,0x13,
197 0x0e,0x8b,0x82,0x6f,0x96,0xc8,0x9a,0x68,0xfc,0x4c,0x02,0xf0,0xdc,0xcd,0x36,0x25,
198 0x31,0xd5,0x82,0xcf,0xc9,0x69,0x72,0xf6,0x1d,0xab,0x68,0x20,0x2e,0x2d,0x19,0x49,
199 0xf0,0x2e,0xad,0xd2,0xda,0xaf,0xff,0xb6,0x92,0x83,0x5b,0x8a,0x06,0x2d,0x0c,0x32,
200 0x11,0x32,0x3b,0x77,0x17,0xf6,0x50,0xfb,0xf8,0x57,0xc9,0xc7,0x9b,0x9e,0xc6,0xd1,
201 0xa9,0x55,0xf0,0x22,0x35,0xda,0xca,0x3c,0x8e,0xc6,0x9a,0xd8,0x25,0xc8,0x5e,0x93,
202 0x0d,0xaa,0xa7,0x06,0xaf,0x11,0x29,0x99,0xe7,0x7c,0xee,0x49,0x82,0x30,0xba,0x2c,
203 0xe2,0x40,0x8f,0x0a,0xa6,0x7b,0x24,0x75,0xc5,0xcd,0x03,0x12,0xf4,0xb2,0x4b,0x3a,
204 0xd1,0x91,0x3c,0x20,0x0e,0x58,0x2b,0x31,0xf8,0x8b,0xee,0xbc,0x1f,0x95,0x35,0x58,
205 0x6a,0x73,0xee,0x99,0xb0,0x01,0x42,0x4f,0x66,0xc0,0x66,0xbb,0x35,0x86,0xeb,0xd9,
206 0x7b,0x55,0x77,0x2d,0x54,0x78,0x19,0x49,0xe8,0xcc,0xfd,0xb1,0xcb,0x49,0xc9,0xea,
207 0x20,0xab,0xed,0xb5,0xed,0xfe,0xb2,0xb5,0xa8,0xcf,0x05,0x06,0xd5,0x7d,0x2b,0xbb,
208 0x0b,0x65,0x6b,0x2b,0x6d,0x55,0x95,0x85,0x44,0x8b,0x12,0x05,0xf3,0x4b,0xd4,0x8e,
209
0x3d,0x68,0x2d,0x29,0x9c,0x05,0x79,0xd6,0xfc,0x72,0x90,0x6a,0xab,0x46,0x38,0x81}};
210
211 const TPM2B_RSA_TEST_VALUE c_RsassaKvt = {RSA_TEST_KEY_SIZE, {
212 0x8a,0xb1,0x0a,0xb5,0xe4,0x02,0xf7,0xdd,0x45,0x2a,0xcc,0x2b,0x6b,0x8c,0x0e,0x9a,
213 0x92,0x4f,0x9b,0xc5,0xe4,0x8b,0x82,0xb9,0xb0,0xd9,0x87,0x8c,0xcb,0xf0,0xb0,0x59,
214 0xa5,0x92,0x21,0xa0,0xa7,0x61,0x5c,0xed,0xa8,0x6e,0x22,0x29,0x46,0xc7,0x86,0x37,
215 0x4b,0x1b,0x1e,0x94,0x93,0xc8,0x4c,0x17,0x7a,0xae,0x59,0x91,0xf8,0x83,0x84,0xc4,
216 0x8c,0x38,0xc2,0x35,0x0e,0x7e,0x50,0x67,0x76,0xe7,0xd3,0xec,0x6f,0x0d,0xa0,0x5c,
217 0x2f,0x0a,0x80,0x28,0xd3,0xc5,0x7d,0x2d,0x1a,0x0b,0x96,0xd6,0xe5,0x98,0x05,0x8c,
218 0x4d,0xa0,0x1f,0x8c,0xb6,0xfb,0xb1,0xcf,0xe9,0xcb,0x38,0x27,0x60,0x64,0x17,0xca,
219 0xf4,0x8b,0x61,0xb7,0x1d,0xb6,0x20,0x9d,0x40,0x2a,0x1c,0xfd,0x55,0x40,0x4b,0x95,
220 0x39,0x52,0x18,0x3b,0xab,0x44,0xe8,0x83,0x4b,0x7c,0x47,0xfb,0xed,0x06,0x9c,0xcd,
221 0x4f,0xba,0x81,0xd6,0xb7,0x31,0xcf,0x5c,0x23,0xf8,0x25,0xab,0x95,0x77,0x0a,0x8f,
222 0x46,0xef,0xfb,0x59,0xb8,0x04,0xd7,0x1e,0xf5,0xaf,0x6a,0x1a,0x26,0x9b,0xae,0xf4,
223 0xf5,0x7f,0x84,0x6f,0x3c,0xed,0xf8,0x24,0x0b,0x43,0xd1,0xba,0x74,0x89,0x4e,0x39,
224 0xfe,0xab,0xa5,0x16,0xa5,0x28,0xee,0x96,0x84,0x3e,0x16,0x6d,0x5f,0x4e,0x0b,0x7d,
225 0x94,0x16,0x1b,0x8c,0xf9,0xaa,0x9b,0xc0,0x49,0x02,0x4c,0x3e,0x62,0xff,0xfe,0xa2,
226 0x20,0x33,0x5e,0xa6,0xdd,0xda,0x15,0x2d,0xb7,0xcd,0xda,0xff,0xb1,0x0b,0x45,0x7b,
227
0xd3,0xa0,0x42,0x29,0xab,0xa9,0x73,0xe9,0xa4,0xd9,0x8d,0xac,0xa1,0x88,0x2c,0x2d}};
228
229 #endif // SHA256
230
231 #if ALG_SHA384_VALUE == DEFAULT_TEST_HASH
232
233 const TPM2B_RSA_TEST_VALUE c_OaepKvt = {RSA_TEST_KEY_SIZE, {
234 0x0f,0x3c,0x42,0x4d,0x8c,0x91,0x96,0x05,0x3c,0xfd,0x59,0x3b,0x7f,0x29,0xbc,0x03,
235 0x67,0xc1,0xff,0x74,0xe7,0x09,0xf4,0x13,0x45,0xbe,0x13,0x1d,0xc9,0x86,0x94,0xfe,
236 0xed,0xa6,0xe8,0x3a,0xcb,0x89,0x4d,0xec,0x86,0x63,0x4c,0xdb,0xf1,0x95,0xee,0xc1,
237 0x46,0xc5,0x3b,0xd8,0xf8,0xa2,0x41,0x6a,0x60,0x8b,0x9e,0x5e,0x7f,0x20,0x16,0xe3,
238 0x69,0xb6,0x2d,0x92,0xfc,0x60,0xa2,0x74,0x88,0xd5,0xc7,0xa6,0xd1,0xff,0xe3,0x45,
239 0x02,0x51,0x39,0xd9,0xf3,0x56,0x0b,0x91,0x80,0xe0,0x6c,0xa8,0xc3,0x78,0xef,0x34,
240 0x22,0x8c,0xf5,0xfb,0x47,0x98,0x5d,0x57,0x8e,0x3a,0xb9,0xff,0x92,0x04,0xc7,0xc2,
241 0x6e,0xfa,0x14,0xc1,0xb9,0x68,0x15,0x5c,0x12,0xe8,0xa8,0xbe,0xea,0xe8,0x8d,0x9b,
242 0x48,0x28,0x35,0xdb,0x4b,0x52,0xc1,0x2d,0x85,0x47,0x83,0xd0,0xe9,0xae,0x90,0x6e,
243 0x65,0xd4,0x34,0x7f,0x81,0xce,0x69,0xf0,0x96,0x62,0xf7,0xec,0x41,0xd5,0xc2,0xe3,
244 0x4b,0xba,0x9c,0x8a,0x02,0xce,0xf0,0x5d,0x14,0xf7,0x09,0x42,0x8e,0x4a,0x27,0xfe,
245 0x3e,0x66,0x42,0x99,0x03,0xe1,0x69,0xbd,0xdb,0x7f,0x9b,0x70,0xeb,0x4e,0x9c,0xac,
246 0x45,0x67,0x91,0x9f,0x75,0x10,0xc6,0xfc,0x14,0xe1,0x28,0xc1,0x0e,0xe0,0x7e,0xc0,
247 0x5c,0x1d,0xee,0xe8,0xff,0x45,0x79,0x51,0x86,0x08,0xe6,0x39,0xac,0xb5,0xfd,0xb8,
248 0xf1,0xdd,0x2e,0xf4,0xb2,0x1a,0x69,0x0d,0xd9,0x98,0x8e,0xdb,0x85,0x61,0x70,0x20,
249
0x82,0x91,0x26,0x87,0x80,0xc4,0x6a,0xd8,0x3b,0x91,0x4d,0xd3,0x33,0x84,0xad,0xb7}};
250
251 const TPM2B_RSA_TEST_VALUE c_RsaesKvt = {RSA_TEST_KEY_SIZE, {
252 0x44,0xd5,0x9f,0xbc,0x48,0x03,0x3d,0x9f,0x22,0x91,0x2a,0xab,0x3c,0x31,0x71,0xab,
253 0x86,0x3f,0x0f,0x6f,0x59,0x5b,0x93,0x27,0xbc,0xbc,0xcd,0x29,0x38,0x43,0x2a,0x3b,
254 0x3b,0xd2,0xb3,0x45,0x40,0xba,0x15,0xb4,0x45,0xe3,0x56,0xab,0xff,0xb3,0x20,0x26,
255 0x39,0xcc,0x48,0xc5,0x5d,0x41,0x0d,0x2f,0x57,0x7f,0x9d,0x16,0x2e,0x26,0x57,0xc7,
256 0x6b,0xf3,0x36,0x54,0xbd,0xb6,0x1d,0x46,0x4e,0x13,0x50,0xd7,0x61,0x9d,0x8d,0x7b,
257 0xeb,0x21,0x9f,0x79,0xf3,0xfd,0xe0,0x1b,0xa8,0xed,0x6d,0x29,0x33,0x0d,0x65,0x94,
258 0x24,0x1e,0x62,0x88,0x6b,0x2b,0x4e,0x39,0xf5,0x80,0x39,0xca,0x76,0x95,0xbc,0x7c,
259 0x27,0x1d,0xdd,0x3a,0x11,0xf1,0x3e,0x54,0x03,0xb7,0x43,0x91,0x99,0x33,0xfe,0x9d,
260 0x14,0x2c,0x87,0x9a,0x95,0x18,0x1f,0x02,0x04,0x6a,0xe2,0xb7,0x81,0x14,0x13,0x45,
261 0x16,0xfb,0xe4,0xb7,0x8f,0xab,0x2b,0xd7,0x60,0x34,0x8a,0x55,0xbc,0x01,0x8c,0x49,
262 0x02,0x29,0xf1,0x9c,0x94,0x98,0x44,0xd0,0x94,0xcb,0xd4,0x85,0x4c,0x3b,0x77,0x72,
263 0x99,0xd5,0x4b,0xc6,0x3b,0xe4,0xd2,0xc8,0xe9,0x6a,0x23,0x18,0x3b,0x3b,0x5e,0x32,
264 0xec,0x70,0x84,0x5d,0xbb,0x6a,0x8f,0x0c,0x5f,0x55,0xa5,0x30,0x34,0x48,0xbb,0xc2,
265 0xdf,0x12,0xb9,0x81,0xad,0x36,0x3f,0xf0,0x24,0x16,0x48,0x04,0x4a,0x7f,0xfd,0x9f,
266 0x4c,0xea,0xfe,0x1d,0x83,0xd0,0x81,0xad,0x25,0x6c,0x5f,0x45,0x36,0x91,0xf0,0xd5,
267
0x8b,0x53,0x0a,0xdf,0xec,0x9f,0x04,0x58,0xc4,0x35,0xa0,0x78,0x1f,0x68,0xe0,0x22}};
268
269 const TPM2B_RSA_TEST_VALUE c_RsapssKvt = {RSA_TEST_KEY_SIZE, {
270 0x3f,0x3a,0x82,0x6d,0x42,0xe3,0x8b,0x4f,0x45,0x9c,0xda,0x6c,0xbe,0xbe,0xcd,0x00,
271 0x98,0xfb,0xbe,0x59,0x30,0xc6,0x3c,0xaa,0xb3,0x06,0x27,0xb5,0xda,0xfa,0xb2,0xc3,
272 0x43,0xb7,0xbd,0xe9,0xd3,0x23,0xed,0x80,0xce,0x74,0xb3,0xb8,0x77,0x8d,0xe6,0x8d,
273 0x3c,0xe5,0xf5,0xd7,0x80,0xcf,0x38,0x55,0x76,0xd7,0x87,0xa8,0xd6,0x3a,0xcf,0xfd,
274 0xd8,0x91,0x65,0xab,0x43,0x66,0x50,0xb7,0x9a,0x13,0x6b,0x45,0x80,0x76,0x86,0x22,
275 0x27,0x72,0xf7,0xbb,0x65,0x22,0x5c,0x55,0x60,0xd8,0x84,0x9f,0xf2,0x61,0x52,0xac,
276 0xf2,0x4f,0x5b,0x7b,0x21,0xe1,0xf5,0x4b,0x8f,0x01,0xf2,0x4b,0xcf,0xd3,0xfb,0x74,
277 0x5e,0x6e,0x96,0xb4,0xa8,0x0f,0x01,0x9b,0x26,0x54,0x0a,0x70,0x55,0x26,0xb7,0x0b,
278 0xe8,0x01,0x68,0x66,0x0d,0x6f,0xb5,0xfc,0x66,0xbd,0x9e,0x44,0xed,0x6a,0x1e,0x3c,
279 0x3b,0x61,0x5d,0xe8,0xdb,0x99,0x5b,0x67,0xbf,0x94,0xfb,0xe6,0x8c,0x4b,0x07,0xcb,
280 0x43,0x3a,0x0d,0xb1,0x1b,0x10,0x66,0x81,0xe2,0x0d,0xe7,0xd1,0xca,0x85,0xa7,0x50,
281 0x82,0x2d,0xbf,0xed,0xcf,0x43,0x6d,0xdb,0x2c,0x7b,0x73,0x20,0xfe,0x73,0x3f,0x19,
282 0xc6,0xdb,0x69,0xb8,0xc3,0xd3,0xf4,0xe5,0x64,0xf8,0x36,0x8e,0xd5,0xd8,0x09,0x2a,
283 0x5f,0x26,0x70,0xa1,0xd9,0x5b,0x14,0xf8,0x22,0xe9,0x9d,0x22,0x51,0xf4,0x52,0xc1,
284 0x6f,0x53,0xf5,0xca,0x0d,0xda,0x39,0x8c,0x29,0x42,0xe8,0x58,0x89,0xbb,0xd1,0x2e,
285
0xc5,0xdb,0x86,0x8d,0xaf,0xec,0x58,0x36,0x8d,0x8d,0x57,0x23,0xd5,0xdd,0xb9,0x24}};
286
287 const TPM2B_RSA_TEST_VALUE c_RsassaKvt = {RSA_TEST_KEY_SIZE, {
288 0x39,0x10,0x58,0x7d,0x6d,0xa8,0xd5,0x90,0x07,0xd6,0x2b,0x13,0xe9,0xd8,0x93,0x7e,
289 0xf3,0x5d,0x71,0xe0,0xf0,0x33,0x3a,0x4a,0x22,0xf3,0xe6,0x95,0xd3,0x8e,0x8c,0x41,
290 0xe7,0xb3,0x13,0xde,0x4a,0x45,0xd3,0xd1,0xfb,0xb1,0x3f,0x9b,0x39,0xa5,0x50,0x58,
291 0xef,0xb6,0x3a,0x43,0xdd,0x54,0xab,0xda,0x9d,0x32,0x49,0xe4,0x57,0x96,0xe5,0x1b,
292 0x1d,0x8f,0x33,0x8e,0x07,0x67,0x56,0x14,0xc1,0x18,0x78,0xa2,0x52,0xe6,0x2e,0x07,
293 0x81,0xbe,0xd8,0xca,0x76,0x63,0x68,0xc5,0x47,0xa2,0x92,0x5e,0x4c,0xfd,0x14,0xc7,
294 0x46,0x14,0xbe,0xc7,0x85,0xef,0xe6,0xb8,0x46,0xcb,0x3a,0x67,0x66,0x89,0xc6,0xee,
295 0x9d,0x64,0xf5,0x0d,0x09,0x80,0x9a,0x6f,0x0e,0xeb,0xe4,0xb9,0xe9,0xab,0x90,0x4f,
296 0xe7,0x5a,0xc8,0xca,0xf6,0x16,0x0a,0x82,0xbd,0xb7,0x76,0x59,0x08,0x2d,0xd9,0x40,
297 0x5d,0xaa,0xa5,0xef,0xfb,0xe3,0x81,0x2c,0x2c,0x5c,0xa8,0x16,0xbd,0x63,0x20,0xc2,
298 0x4d,0x3b,0x51,0xaa,0x62,0x1f,0x06,0xe5,0xbb,0x78,0x44,0x04,0x0c,0x5c,0xe1,0x1b,
299 0x6b,0x9d,0x21,0x10,0xaf,0x48,0x48,0x98,0x97,0x77,0xc2,0x73,0xb4,0x98,0x64,0xcc,
300 0x94,0x2c,0x29,0x28,0x45,0x36,0xd1,0xc5,0xd0,0x2f,0x97,0x27,0x92,0x65,0x22,0xbb,
301 0x63,0x79,0xea,0xf5,0xff,0x77,0x0f,0x4b,0x56,0x8a,0x9f,0xad,0x1a,0x97,0x67,0x39,
302 0x69,0xb8,0x4c,0x6c,0xc2,0x56,0xc5,0x7a,0xa8,0x14,0x5a,0x24,0x7a,0xa4,0x6e,0x55,
303
0xb2,0x86,0x1d,0xf4,0x62,0x5a,0x2d,0x87,0x6d,0xde,0x99,0x78,0x2d,0xef,0xd7,0xdc}};
304
305 #endif // SHA384
306
307 #if ALG_SHA512_VALUE == DEFAULT_TEST_HASH
308
309 const TPM2B_RSA_TEST_VALUE c_OaepKvt = {RSA_TEST_KEY_SIZE, {
310 0x48,0x45,0xa7,0x70,0xb2,0x41,0xb7,0x48,0x5e,0x79,0x8c,0xdf,0x1c,0xc6,0x7e,0xbb,
311 0x11,0x80,0x82,0x52,0xbf,0x40,0x3d,0x90,0x03,0x6e,0x20,0x3a,0xb9,0x65,0xc8,0x51,
312 0x4c,0xbd,0x9c,0xa9,0x43,0x89,0xd0,0x57,0x0c,0xa3,0x69,0x22,0x7e,0x82,0x2a,0x1c,
313 0x1d,0x5a,0x80,0x84,0x81,0xbb,0x5e,0x5e,0xd0,0xc1,0x66,0x9a,0xac,0x00,0xba,0x14,
314 0xa2,0xe9,0xd0,0x3a,0x89,0x5a,0x63,0xe2,0xec,0x92,0x05,0xf4,0x47,0x66,0x12,0x7f,
315 0xdb,0xa7,0x3c,0x5b,0x67,0xe1,0x55,0xca,0x0a,0x27,0xbf,0x39,0x89,0x11,0x05,0xba,
316 0x9b,0x5a,0x9b,0x65,0x44,0xad,0x78,0xcf,0x8f,0x94,0xf6,0x9a,0xb4,0x52,0x39,0x0e,
317 0x00,0xba,0xbc,0xe0,0xbd,0x6f,0x81,0x2d,0x76,0x42,0x66,0x70,0x07,0x77,0xbf,0x09,
318 0x88,0x2a,0x0c,0xb1,0x56,0x3e,0xee,0xfd,0xdc,0xb6,0x3c,0x0d,0xc5,0xa4,0x0d,0x10,
319 0x32,0x80,0x3e,0x1e,0xfe,0x36,0x8f,0xb5,0x42,0xc1,0x21,0x7b,0xdf,0xdf,0x4a,0xd2,
320 0x68,0x0c,0x01,0x9f,0x4a,0xfd,0xd4,0xec,0xf7,0x49,0x06,0xab,0xed,0xc6,0xd5,0x1b,
321 0x63,0x76,0x38,0xc8,0x6c,0xc7,0x4f,0xcb,0x29,0x8a,0x0e,0x6f,0x33,0xaf,0x69,0x31,
322 0x8e,0xa7,0xdd,0x9a,0x36,0xde,0x9b,0xf1,0x0b,0xfb,0x20,0xa0,0x6d,0x33,0x31,0xc9,
323 0x9e,0xb4,0x2e,0xc5,0x40,0x0e,0x60,0x71,0x36,0x75,0x05,0xf9,0x37,0xe0,0xca,0x8e,
324 0x8f,0x56,0xe0,0xea,0x9b,0xeb,0x17,0xf3,0xca,0x40,0xc3,0x48,0x01,0xba,0xdc,0xc6,
325
0x4b,0x2b,0x5b,0x7b,0x5c,0x81,0xa6,0xbb,0xc7,0x43,0xc0,0xbe,0xc0,0x30,0x7b,0x55}};
326
327 const TPM2B_RSA_TEST_VALUE c_RsaesKvt = {RSA_TEST_KEY_SIZE, {
328 0x74,0x83,0xfa,0x52,0x65,0x50,0x68,0xd0,0x82,0x05,0x72,0x70,0x78,0x1c,0xac,0x10,
329 0x23,0xc5,0x07,0xf8,0x93,0xd2,0xeb,0x65,0x87,0xbb,0x47,0xc2,0xfb,0x30,0x9e,0x61,
330 0x4c,0xac,0x04,0x57,0x5a,0x7c,0xeb,0x29,0x08,0x84,0x86,0x89,0x1e,0x8f,0x07,0x32,
331 0xa3,0x8b,0x70,0xe7,0xa2,0x9f,0x9c,0x42,0x71,0x3d,0x23,0x59,0x82,0x5e,0x8a,0xde,
332 0xd6,0xfb,0xd8,0xc5,0x8b,0xc0,0xdb,0x10,0x38,0x87,0xd3,0xbf,0x04,0xb0,0x66,0xb9,
333 0x85,0x81,0x54,0x4c,0x69,0xdc,0xba,0x78,0xf3,0x4a,0xdb,0x25,0xa2,0xf2,0x34,0x55,
334 0xdd,0xaa,0xa5,0xc4,0xed,0x55,0x06,0x0e,0x2a,0x30,0x77,0xab,0x82,0x79,0xf0,0xcd,
335 0x9d,0x6f,0x09,0xa0,0xc8,0x82,0xc9,0xe0,0x61,0xda,0x40,0xcd,0x17,0x59,0xc0,0xef,
336 0x95,0x6d,0xa3,0x6d,0x1c,0x2b,0xee,0x24,0xef,0xd8,0x4a,0x55,0x6c,0xd6,0x26,0x42,
337 0x32,0x17,0xfd,0x6a,0xb3,0x4f,0xde,0x07,0x2f,0x10,0xd4,0xac,0x14,0xea,0x89,0x68,
338 0xcc,0xd3,0x07,0xb7,0xcf,0xba,0x39,0x20,0x63,0x20,0x7b,0x44,0x8b,0x48,0x60,0x5d,
339 0x3a,0x2a,0x0a,0xe9,0x68,0xab,0x15,0x46,0x27,0x64,0xb5,0x82,0x06,0x29,0xe7,0x25,
340 0xca,0x46,0x48,0x6e,0x2a,0x34,0x57,0x4b,0x81,0x75,0xae,0xb6,0xfd,0x6f,0x51,0x5f,
341 0x04,0x59,0xc7,0x15,0x1f,0xe0,0x68,0xf7,0x36,0x2d,0xdf,0xc8,0x9d,0x05,0x27,0x2d,
342 0x3f,0x2b,0x59,0x5d,0xcb,0xf3,0xc4,0x92,0x6e,0x00,0xa8,0x8d,0xd0,0x69,0xe5,0x59,
343
0xda,0xba,0x4f,0x38,0xf5,0xa0,0x8b,0xf1,0x73,0xe9,0x0d,0xee,0x64,0xe5,0xa2,0xd8}};
344
345 const TPM2B_RSA_TEST_VALUE c_RsapssKvt = {RSA_TEST_KEY_SIZE, {
346 0x1b,0xca,0x8b,0x18,0x15,0x3b,0x95,0x5b,0x0a,0x89,0x10,0x03,0x7f,0x7c,0xa0,0xc9,
347 0x66,0x57,0x86,0x6a,0xc9,0xeb,0x82,0x71,0xf3,0x8d,0x6f,0xa9,0xa4,0x2d,0xd0,0x22,
348 0xdf,0xe9,0xc6,0x71,0x5b,0xf4,0x27,0x38,0x5b,0x2c,0x8a,0x54,0xcc,0x85,0x11,0x69,
349 0x6d,0x6f,0x42,0xe7,0x22,0xcb,0xd6,0xad,0x1a,0xc5,0xab,0x6a,0xa5,0xfc,0xa5,0x70,
350 0x72,0x4a,0x62,0x25,0xd0,0xa2,0x16,0x61,0xab,0xac,0x31,0xa0,0x46,0x24,0x4f,0xdd,
351 0x9a,0x36,0x55,0xb6,0x00,0x9e,0x23,0x50,0x0d,0x53,0x01,0xb3,0x46,0x56,0xb2,0x1d,
352 0x33,0x5b,0xca,0x41,0x7f,0x65,0x7e,0x00,0x5c,0x12,0xff,0x0a,0x70,0x5d,0x8c,0x69,
353 0x4a,0x02,0xee,0x72,0x30,0xa7,0x5c,0xa4,0xbb,0xbe,0x03,0x0c,0xe4,0x5f,0x33,0xb6,
354 0x78,0x91,0x9d,0xd8,0xec,0x34,0x03,0x2e,0x63,0x32,0xc7,0x2a,0x36,0x50,0xd5,0x8b,
355 0x0e,0x7f,0x54,0x4e,0xf4,0x29,0x11,0x1b,0xcd,0x0f,0x37,0xa5,0xbc,0x61,0x83,0x50,
356 0xfa,0x18,0x75,0xd9,0xfe,0xa7,0xe8,0x9b,0xc1,0x4f,0x96,0x37,0x81,0x71,0xdf,0x71,
357 0x8b,0x89,0x81,0xf4,0x95,0xb5,0x29,0x66,0x41,0x0c,0x73,0xd7,0x0b,0x21,0xb4,0xfb,
358 0xf9,0x63,0x2f,0xe9,0x7b,0x38,0xaa,0x20,0xc3,0x96,0xcc,0xb7,0xb2,0x24,0xa1,0xe0,
359 0x59,0x9c,0x10,0x9e,0x5a,0xf7,0xe3,0x02,0xe6,0x23,0xe2,0x44,0x21,0x3f,0x6e,0x5e,
360 0x79,0xb2,0x93,0x7d,0xce,0xed,0xe2,0xe1,0xab,0x98,0x07,0xa7,0xbd,0xbc,0xd8,0xf7,
361
0x06,0xeb,0xc5,0xa6,0x37,0x18,0x11,0x88,0xf7,0x63,0x39,0xb9,0x57,0x29,0xdc,0x03}};
362
363 const TPM2B_RSA_TEST_VALUE c_RsassaKvt = {RSA_TEST_KEY_SIZE, {
364 0x05,0x55,0x00,0x62,0x01,0xc6,0x04,0x31,0x55,0x73,0x3f,0x2a,0xf9,0xd4,0x0f,0xc1,
365 0x2b,0xeb,0xd8,0xc8,0xdb,0xb2,0xab,0x6c,0x26,0xde,0x2d,0x89,0xc2,0x2d,0x36,0x62,
366 0xc8,0x22,0x5d,0x58,0x03,0xb1,0x46,0x14,0xa5,0xd4,0xbc,0x25,0x6b,0x7f,0x8f,0x14,
367 0x7e,0x03,0x2f,0x3d,0xb8,0x39,0xa5,0x79,0x13,0x7e,0x22,0x2a,0xb9,0x3e,0x8f,0xaa,
368 0x01,0x7c,0x03,0x12,0x21,0x6c,0x2a,0xb4,0x39,0x98,0x6d,0xff,0x08,0x6c,0x59,0x2d,
369 0xdc,0xc6,0xf1,0x77,0x62,0x10,0xa6,0xcc,0xe2,0x71,0x8e,0x97,0x00,0x87,0x5b,0x0e,
370 0x20,0x00,0x3f,0x18,0x63,0x83,0xf0,0xe4,0x0a,0x64,0x8c,0xe9,0x8c,0x91,0xe7,0x89,
371 0x04,0x64,0x2c,0x8b,0x41,0xc8,0xac,0xf6,0x5a,0x75,0xe6,0xa5,0x76,0x43,0xcb,0xa5,
372 0x33,0x8b,0x07,0xc9,0x73,0x0f,0x45,0xa4,0xc3,0xac,0xc1,0xc3,0xe6,0xe7,0x21,0x66,
373 0x1c,0xba,0xbf,0xea,0x3e,0x39,0xfa,0xb2,0xe2,0x8f,0xfe,0x9c,0xb4,0x85,0x89,0x33,
374 0x2a,0x0c,0xc8,0x5d,0x58,0xe1,0x89,0x12,0xe9,0x4d,0x42,0xb3,0x1f,0x99,0x0c,0x3e,
375 0xd8,0xb2,0xeb,0xf5,0x88,0xfb,0xe1,0x4b,0x8e,0xdc,0xd3,0xa8,0xda,0xbe,0x04,0x45,
376 0xbf,0x56,0xc6,0x54,0x70,0x00,0xb8,0x66,0x46,0x3a,0xa3,0x1e,0xb6,0xeb,0x1a,0xa0,
377 0x0b,0xd3,0x9a,0x9a,0x52,0xda,0x60,0x69,0xb7,0xef,0x93,0x47,0x38,0xab,0x1a,0xa0,
378 0x22,0x6e,0x76,0x06,0xb6,0x74,0xaf,0x74,0x8f,0x51,0xc0,0x89,0x5a,0x4b,0xbe,0x6a,
379
0x91,0x18,0x25,0x7d,0xa6,0x77,0xe6,0xfd,0xc2,0x62,0x36,0x07,0xc6,0xef,0x79,0xc9}};
380
381 #endif // SHA512
10.1.10 SelfTest.h
10.1.10.1 Introduction
This file contains the structure definitions for the self-test. It also contains macros for use when the self-
test is implemented.
1 #ifndef _SELF_TEST_H_
2 #define _SELF_TEST_H_
10.1.10.2 Defines
Use the definition of key sizes to set algorithm values for key size.
These two defines deal with the fact that the TPM_ALG_ID table does not delimit the symmetric mode
values with a TPM_SYM_MODE_FIRST and TPM_SYM_MODE_LAST
10.1.11 SupportLibraryFunctionPrototypes_fp.h
10.1.11.1 Introduction
This file contains the function prototypes for the functions that need to be present in the selected math
library. For each function listed, there should be a small stub function. That stub provides the interface
between the TPM code and the support library. In most cases, the stub function will only need to do a
format conversion between the TPM big number and the support library big number. The TPM big
number format was chosen to make this relatively simple and fast.
Arithmetic operations return a BOOL to indicate if the operation completed successfully or not.
1 #ifndef SUPPORT_LIBRARY_FUNCTION_PROTOTYPES_H
2 #define SUPPORT_LIBRARY_FUNCTION_PROTOTYPES_H
10.1.11.2 SupportLibInit()
This function is called by CryptInit() so that necessary initializations can be performed on the
cryptographic library.
3 LIB_EXPORT
4 int SupportLibInit(void);
10.1.11.3 MathLibraryCompatibililtyCheck()
This function is only used during development to make sure that the library that is being referenced is
using the same size of data structures as the TPM.
5 BOOL
6 MathLibraryCompatibilityCheck(
7 void
8 );
10.1.11.4 BnModMult()
Does op1 * op2 and divide by modulus returning the remainder of the divide.
9 LIB_EXPORT BOOL
10 BnModMult(bigNum result, bigConst op1, bigConst op2, bigConst modulus);
10.1.11.5 BnMult()
11 LIB_EXPORT BOOL
12 BnMult(bigNum result, bigConst multiplicand, bigConst multiplier);
10.1.11.6 BnDiv()
This function divides two bigNum values. The function returns FALSE if there is an error in the operation.
13 LIB_EXPORT BOOL
14 BnDiv(bigNum quotient, bigNum remainder,
15 bigConst dividend, bigConst divisor);
10.1.11.7 BnMod()
10.1.11.8 BnGcd()
Get the greatest common divisor of two numbers. This function is only needed when the TPM implements
RSA.
17 LIB_EXPORT BOOL
18 BnGcd(bigNum gcd, bigConst number1, bigConst number2);
10.1.11.9 BnModExp()
Do modular exponentiation using bigNum values. This function is only needed when the TPM implements
RSA.
19 LIB_EXPORT BOOL
20 BnModExp(bigNum result, bigConst number,
21 bigConst exponent, bigConst modulus);
10.1.11.10 BnModInverse()
Modular multiplicative inverse. This function is only needed when the TPM implements RSA.
10.1.11.11 BnEccModMult()
This function does a point multiply of the form R = [d]S. A return of FALSE indicates that the result was
the point at infinity. This function is only needed if the TPM supports ECC.
24 LIB_EXPORT BOOL
25 BnEccModMult(bigPoint R, pointConst S, bigConst d, bigCurve E);
10.1.11.12 BnEccModMult2()
This function does a point multiply of the form R = [d]S + [u]Q. A return of FALSE indicates that the result
was the point at infinity. This function is only needed if the TPM supports ECC.
26 LIB_EXPORT BOOL
27 BnEccModMult2(bigPoint R, pointConst S, bigConst d,
28 pointConst Q, bigConst u, bigCurve E);
10.1.11.13 BnEccAdd()
This function does a point add R = S + Q. A return of FALSE indicates that the result was the point at
infinity. This function is only needed if the TPM supports ECC.
29 LIB_EXPORT BOOL
30 BnEccAdd(bigPoint R, pointConst S, pointConst Q, bigCurve E);
10.1.11.14 BnCurveInitialize()
This function is used to initialize the pointers of a bnCurve_t structure. The structure is a set of pointers to
bigNum values. The curve-dependent values are set by a different function. This function is only needed if
the TPM supports ECC.
31 LIB_EXPORT bigCurve
32 BnCurveInitialize(bigCurve E, TPM_ECC_CURVE curveId);
10.1.11.14.1 BnCurveFree()
This function will free the allocated components of the curve and end the frame in which the curve data
exists
33 LIB_EXPORT void
34 BnCurveFree(bigCurve E);
35 #endif
10.1.12 SymmetricTestData.h
This is a vector for testing either encrypt or decrypt. The premise for decrypt is that the IV for decryption is
the same as the IV for encryption. However, the ivOut value may be different for encryption and
decryption. We will encrypt at least two blocks. This means that the chaining value will be used for each
of the schemes (if any) and that implicitly checks that the chaining value is handled properly.
1 #if AES_128
2 const BYTE key_AES128 [] = {
3 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
4 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
5
6 const BYTE dataIn_AES128 [] = {
7 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
8 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
9 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
10 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51};
11
12 const BYTE dataOut_AES128_ECB [] = {
13 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
14 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
15 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
16 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf};
17
18 const BYTE dataOut_AES128_CBC [] = {
19 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
20 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
21 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
22 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2};
23
24 const BYTE dataOut_AES128_CFB [] = {
25 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
26 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
27 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f,
28 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b};
29
30 const BYTE dataOut_AES128_OFB [] = {
31 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
32 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
33 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03,
34 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25};
35
36 const BYTE dataOut_AES128_CTR [] = {
37 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
38 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
39 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
40 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff};
41 #endif
42
43 #if AES_192
44
45 const BYTE key_AES192 [] = {
46 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
47 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
48 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b};
49
50 const BYTE dataIn_AES192 [] = {
51 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
52 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
53 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
54 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51};
55
10.1.13 SymmetricTest.h
10.1.13.1 Introduction
This file contains the structures and data definitions for the symmetric tests. This file references the
header file that contains the actual test vectors. This organization was chosen so that the program that is
used to generate the test vector values does not have to also re-generate this data.
1 #ifndef SELF_TEST_DATA
2 #error "This file may only be included in AlgorithmTests.c"
3 #endif
4 #ifndef _SYMMETRIC_TEST_H
5 #define _SYMMETRIC_TEST_H
6 #include "SymmetricTestData.h"
10.1.14 EccTestData.h
1 #ifdef SELF_TEST_DATA
2 TPM2B_TYPE(EC_TEST, 32);
3 const TPM_ECC_CURVE c_testCurve = 00003;
4
5 // The "static" key
6
7 const TPM2B_EC_TEST c_ecTestKey_ds = {{32, {
8 0xdf,0x8d,0xa4,0xa3,0x88,0xf6,0x76,0x96,0x89,0xfc,0x2f,0x2d,0xa1,0xb4,0x39,0x7a,
9
0x78,0xc4,0x7f,0x71,0x8c,0xa6,0x91,0x85,0xc0,0xbf,0xf3,0x54,0x20,0x91,0x2f,0x73}}}
;
10
11 const TPM2B_EC_TEST c_ecTestKey_QsX = {{32, {
12 0x17,0xad,0x2f,0xcb,0x18,0xd4,0xdb,0x3f,0x2c,0x53,0x13,0x82,0x42,0x97,0xff,0x8d,
13
0x99,0x50,0x16,0x02,0x35,0xa7,0x06,0xae,0x1f,0xda,0xe2,0x9c,0x12,0x77,0xc0,0xf9}}}
;
14
15 const TPM2B_EC_TEST c_ecTestKey_QsY = {{32, {
16 0xa6,0xca,0xf2,0x18,0x45,0x96,0x6e,0x58,0xe6,0x72,0x34,0x12,0x89,0xcd,0xaa,0xad,
17
0xcb,0x68,0xb2,0x51,0xdc,0x5e,0xd1,0x6d,0x38,0x20,0x35,0x57,0xb2,0xfd,0xc7,0x52}}}
;
18
19 // The "ephemeral" key
20
21 const TPM2B_EC_TEST c_ecTestKey_de = {{32, {
22 0xb6,0xb5,0x33,0x5c,0xd1,0xee,0x52,0x07,0x99,0xea,0x2e,0x8f,0x8b,0x19,0x18,0x07,
23
0xc1,0xf8,0xdf,0xdd,0xb8,0x77,0x00,0xc7,0xd6,0x53,0x21,0xed,0x02,0x53,0xee,0xac}}}
;
24
25 const TPM2B_EC_TEST c_ecTestKey_QeX = {{32, {
26 0xa5,0x1e,0x80,0xd1,0x76,0x3e,0x8b,0x96,0xce,0xcc,0x21,0x82,0xc9,0xa2,0xa2,0xed,
27
0x47,0x21,0x89,0x53,0x44,0xe9,0xc7,0x92,0xe7,0x31,0x48,0x38,0xe6,0xea,0x93,0x47}}}
;
28
29 const TPM2B_EC_TEST c_ecTestKey_QeY = {{32, {
30 0x30,0xe6,0x4f,0x97,0x03,0xa1,0xcb,0x3b,0x32,0x2a,0x70,0x39,0x94,0xeb,0x4e,0xea,
31
0x55,0x88,0x81,0x3f,0xb5,0x00,0xb8,0x54,0x25,0xab,0xd4,0xda,0xfd,0x53,0x7a,0x18}}}
;
32
33 // ECDH test results
34 const TPM2B_EC_TEST c_ecTestEcdh_X = {{32, {
35 0x64,0x02,0x68,0x92,0x78,0xdb,0x33,0x52,0xed,0x3b,0xfa,0x3b,0x74,0xa3,0x3d,0x2c,
36
0x2f,0x9c,0x59,0x03,0x07,0xf8,0x22,0x90,0xed,0xe3,0x45,0xf8,0x2a,0x0a,0xd8,0x1d}}}
;
37
38 const TPM2B_EC_TEST c_ecTestEcdh_Y = {{32, {
39 0x58,0x94,0x05,0x82,0xbe,0x5f,0x33,0x02,0x25,0x90,0x3a,0x33,0x90,0x89,0xe3,0xe5,
40
0x10,0x4a,0xbc,0x78,0xa5,0xc5,0x07,0x64,0xaf,0x91,0xbc,0xe6,0xff,0x85,0x11,0x40}}}
;
41
42 TPM2B_TYPE(TEST_VALUE, 64);
88 0xf5,0x74,0x6d,0xd6,0xc6,0x56,0x86,0xbb,0xba,0x1c,0xba,0x75,0x65,0xee,0x64,0x31,
89
0xce,0x04,0xe3,0x9f,0x24,0x3f,0xbd,0xfe,0x04,0xcd,0xab,0x7e,0xfe,0xad,0xcb,0x82}}}
;
90 const TPM2B_EC_TEST c_TestEcDsa_s = {{32, {
91 0xc2,0x4f,0x32,0xa1,0x06,0xc0,0x85,0x4f,0xc6,0xd8,0x31,0x66,0x91,0x9f,0x79,0xcd,
92
0x5b,0xe5,0x7b,0x94,0xa1,0x91,0x38,0xac,0xd4,0x20,0xa2,0x10,0xf0,0xd5,0x9d,0xbf}}}
;
93
94 const TPM2B_EC_TEST c_TestEcSchnorr_r = {{32, {
95 0x1e,0xb8,0xe1,0xbf,0xa1,0x9e,0x39,0x1e,0x58,0xa2,0xe6,0x59,0xd0,0x1a,0x6a,0x03,
96
0x6a,0x1f,0x1c,0x4f,0x36,0x19,0xc1,0xec,0x30,0xa4,0x85,0x1b,0xe9,0x74,0x35,0x66}}}
;
97 const TPM2B_EC_TEST c_TestEcSchnorr_s = {{32,{
98 0xb9,0xe6,0xe3,0x7e,0xcb,0xb9,0xea,0xf1,0xcc,0xf4,0x48,0x44,0x4a,0xda,0xc8,0xd7,
99
0x87,0xb4,0xba,0x40,0xfe,0x5b,0x68,0x11,0x14,0xcf,0xa0,0x0e,0x85,0x46,0x99,0x01}}}
;
100
101 #endif // SHA384
102
103 #if ALG_SHA512_VALUE == DEFAULT_TEST_HASH
104
105 const TPM2B_EC_TEST c_TestEcDsa_r = {{32, {
106 0xc9,0x71,0xa6,0xb4,0xaf,0x46,0x26,0x8c,0x27,0x00,0x06,0x3b,0x00,0x0f,0xa3,0x17,
107
0x72,0x48,0x40,0x49,0x4d,0x51,0x4f,0xa4,0xcb,0x7e,0x86,0xe9,0xe7,0xb4,0x79,0xb2}}}
;
108 const TPM2B_EC_TEST c_TestEcDsa_s = {{32,{
109 0x87,0xbc,0xc0,0xed,0x74,0x60,0x9e,0xfa,0x4e,0xe8,0x16,0xf3,0xf9,0x6b,0x26,0x07,
110
0x3c,0x74,0x31,0x7e,0xf0,0x62,0x46,0xdc,0xd6,0x45,0x22,0x47,0x3e,0x0c,0xa0,0x02}}}
;
111
112 const TPM2B_EC_TEST c_TestEcSchnorr_r = {{32,{
113 0xcc,0x07,0xad,0x65,0x91,0xdd,0xa0,0x10,0x23,0xae,0x53,0xec,0xdf,0xf1,0x50,0x90,
114
0x16,0x96,0xf4,0x45,0x09,0x73,0x9c,0x84,0xb5,0x5c,0x5f,0x08,0x51,0xcb,0x60,0x01}}}
;
115 const TPM2B_EC_TEST c_TestEcSchnorr_s = {{32,{
116 0x55,0x20,0x21,0x54,0xe2,0x49,0x07,0x47,0x71,0xf4,0x99,0x15,0x54,0xf3,0xab,0x14,
117
0xdb,0x8e,0xda,0x79,0xb6,0x02,0x0e,0xe3,0x5e,0x6f,0x2c,0xb6,0x05,0xbd,0x14,0x10}}}
;
118
119 #endif // SHA512
120
121 #endif // SELF_TEST_DATA
10.1.15 CryptSym.h
10.1.15.1 Introduction
This file contains the implementation of the symmetric block cipher modes allowed for a TPM. These
functions only use the single block encryption functions of the selected symmetric cryptographic library.
1 #ifndef CRYPT_SYM_H
2 #define CRYPT_SYM_H
3 typedef union tpmCryptKeySchedule_t {
4 #if ALG_AES
5 tpmKeyScheduleAES AES;
6 #endif
7 #if ALG_SM4
8 tpmKeyScheduleSM4 SM4;
9 #endif
10 #if ALG_CAMELLIA
11 tpmKeyScheduleCAMELLIA CAMELLIA;
12 #endif
13
14 #if ALG_TDES
15 tpmKeyScheduleTDES TDES[3];
16 #endif
17 #if SYMMETRIC_ALIGNMENT == 8
18 uint64_t alignment;
19 #else
20 uint32_t alignment;
21 #endif
22 } tpmCryptKeySchedule_t;
Each block cipher within a library is expected to conform to the same calling conventions with three
parameters (keySchedule, in, and out) in the same order. That means that all algorithms would use the
same order of the same parameters. The code is written assuming the (keySchedule, in, and out) order.
However, if the library uses a different order, the order can be changed with a SWIZZLE macro that puts
the parameters in the correct order. Note that all algorithms have to use the same order and number of
parameters because the code to build the calling list is common for each call to encrypt or decrypt with
the algorithm chosen by setting a function pointer to select the algorithm that is used.
Note that the macros rely on encrypt as local values in the functions that use these macros. Those
parameters are set by the macro that set the key schedule to be used for the call.
27 #define ENCRYPT_CASE(ALG) \
28 case TPM_ALG_##ALG: \
29 TpmCryptSetEncryptKey##ALG(key, keySizeInBits, &keySchedule.ALG); \
30 encrypt = (TpmCryptSetSymKeyCall_t)TpmCryptEncrypt##ALG; \
31 break;
32 #define DECRYPT_CASE(ALG) \
33 case TPM_ALG_##ALG: \
34 TpmCryptSetDecryptKey##ALG(key, keySizeInBits, &keySchedule.ALG); \
35 decrypt = (TpmCryptSetSymKeyCall_t)TpmCryptDecrypt##ALG; \
36 break;
37 #if ALG_AES
38 #define ENCRYPT_CASE_AES ENCRYPT_CASE(AES)
65 #define SELECT(direction) \
66 switch(algorithm) \
67 { \
68 direction##_CASE_AES \
69 direction##_CASE_SM4 \
70 direction##_CASE_CAMELLIA \
71 direction##_CASE_TDES \
72 default: \
73 FAIL(FATAL_ERROR_INTERNAL); \
74 }
75 #endif // CRYPT_SYM_H
10.1.16 OIDs.h
1 #ifndef _OIDS_H_
2 #define _OIDS_H_
All the OIDs in this file are defined as DER-encoded values with a leading tag 0x06
(ASN1_OBJECT_IDENTIFIER), followed by a single length byte. This allows the OID size to be
determined by looking at octet[1] of the OID (total size is OID[1] + 2). These macros allow OIDs to be
defined (or not) depending on whether the associated hash algorithm is implemented.
NOTE: When one of these macros is used, the NAME needs '_" on each side. The exception is when the macro is
used for the hash OID when only a single _ is used.
3 #ifndef ALG_SHA1
4 # define ALG_SHA1 NO
5 #endif
6 #if ALG_SHA1
7 #define SHA1_OID(NAME) MAKE_OID(NAME##SHA1)
8 #else
9 #define SHA1_OID(NAME)
10 #endif
11 #ifndef ALG_SHA256
12 # define ALG_SHA256 NO
13 #endif
14 #if ALG_SHA256
15 #define SHA256_OID(NAME) MAKE_OID(NAME##SHA256)
16 #else
17 #define SHA256_OID(NAME)
18 #endif
19 #ifndef ALG_SHA384
20 # define ALG_SHA384 NO
21 #endif
22 #if ALG_SHA384
23 #define SHA384_OID(NAME) MAKE_OID(NAME##SHA384)
24 #else
25 #define SHA#84_OID(NAME)
26 #endif
27 #ifndef ALG_SHA512
28 # define ALG_SHA512 NO
29 #endif
30 #if ALG_SHA512
31 #define SHA512_OID(NAME) MAKE_OID(NAME##SHA512)
32 #else
33 #define SHA512_OID(NAME)
34 #endif
35 #ifndef ALG_SM3_256
36 # define ALG_SM3_256 NO
37 #endif
38 #if ALG_SM3_256
39 #define SM3_256_OID(NAME) MAKE_OID(NAME##SM3_256)
40 #else
41 #define SM3_256_OID(NAME)
42 #endif
43 #ifndef ALG_SHA3_256
44 # define ALG_SHA3_256 NO
45 #endif
46 #if ALG_SHA3_256
47 #define SHA3_256_OID(NAME) MAKE_OID(NAME##SHA3_256)
48 #else
49 #define SHA3_256_OID(NAME)
50 #endif
51 #ifndef ALG_SHA3_384
52 # define ALG_SHA3_384 NO
53 #endif
54 #if ALG_SHA3_384
55 #define SHA3_384_OID(NAME) MAKE_OID(NAME##SHA3_384)
56 #else
57 #define SHA3_384_OID(NAME)
58 #endif
59 #ifndef ALG_SHA3_512
60 # define ALG_SHA3_512 NO
61 #endif
62 #if ALG_SHA3_512
63 #define SSHA3_512_OID(NAME) MAKE_OID(NAME##SHA3_512)
64 #else
65 #define SHA3_512_OID(NAME)
66 #endif
94 #if ALG_RSA
95 #define OID_MGF1_VALUE 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, \
96 0x01, 0x01, 0x08
97 MAKE_OID(_MGF1);
98 #define OID_RSAPSS_VALUE 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, \
99 0x01, 0x01, 0x0A
100 MAKE_OID(_RSAPSS);
101 #define OID_PKCS1_PUB_VALUE 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, \
102 0x01, 0x01, 0x01
103 MAKE_OID(_PKCS1_PUB);
10.1.17 PRNG_TestVectors.h
1 #ifndef _MSBN_DRBG_TEST_VECTORS_H
2 #define _MSBN_DRBG_TEST_VECTORS_H
3 //#if DRBG_ALGORITHM == TPM_ALG_AES && DRBG_KEY_BITS == 256
4 #if DRBG_KEY_SIZE_BITS == 256
Entropy is the size of the state. The state is the size of the key plus the IV. The IV is a block. If Key = 256
and Block = 128 then State = 384
5 # define DRBG_TEST_INITIATE_ENTROPY \
6 0x0d, 0x15, 0xaa, 0x80, 0xb1, 0x6c, 0x3a, 0x10, \
7 0x90, 0x6c, 0xfe, 0xdb, 0x79, 0x5d, 0xae, 0x0b, \
8 0x5b, 0x81, 0x04, 0x1c, 0x5c, 0x5b, 0xfa, 0xcb, \
9 0x37, 0x3d, 0x44, 0x40, 0xd9, 0x12, 0x0f, 0x7e, \
10 0x3d, 0x6c, 0xf9, 0x09, 0x86, 0xcf, 0x52, 0xd8, \
11 0x5d, 0x3e, 0x94, 0x7d, 0x8c, 0x06, 0x1f, 0x91
12 # define DRBG_TEST_RESEED_ENTROPY \
13 0x6e, 0xe7, 0x93, 0xa3, 0x39, 0x55, 0xd7, 0x2a, \
14 0xd1, 0x2f, 0xd8, 0x0a, 0x8a, 0x3f, 0xcf, 0x95, \
15 0xed, 0x3b, 0x4d, 0xac, 0x57, 0x95, 0xfe, 0x25, \
16 0xcf, 0x86, 0x9f, 0x7c, 0x27, 0x57, 0x3b, 0xbc, \
17 0x56, 0xf1, 0xac, 0xae, 0x13, 0xa6, 0x50, 0x42, \
18 0xb3, 0x40, 0x09, 0x3c, 0x46, 0x4a, 0x7a, 0x22
19 # define DRBG_TEST_GENERATED_INTERM \
20 0x28, 0xe0, 0xeb, 0xb8, 0x21, 0x01, 0x66, 0x50, \
21 0x8c, 0x8f, 0x65, 0xf2, 0x20, 0x7b, 0xd0, 0xa3
22 # define DRBG_TEST_GENERATED \
23 0x94, 0x6f, 0x51, 0x82, 0xd5, 0x45, 0x10, 0xb9, \
24 0x46, 0x12, 0x48, 0xf5, 0x71, 0xca, 0x06, 0xc9
25 #elif DRBG_KEY_SIZE_BITS == 128
26 # define DRBG_TEST_INITIATE_ENTROPY \
27 0x8f, 0xc1, 0x1b, 0xdb, 0x5a, 0xab, 0xb7, 0xe0, \
28 0x93, 0xb6, 0x14, 0x28, 0xe0, 0x90, 0x73, 0x03, \
29 0xcb, 0x45, 0x9f, 0x3b, 0x60, 0x0d, 0xad, 0x87, \
30 0x09, 0x55, 0xf2, 0x2d, 0xa8, 0x0a, 0x44, 0xf8
31 # define DRBG_TEST_RESEED_ENTROPY \
32 0x0c, 0xd5, 0x3c, 0xd5, 0xec, 0xcd, 0x5a, 0x10, \
33 0xd7, 0xea, 0x26, 0x61, 0x11, 0x25, 0x9b, 0x05, \
34 0x57, 0x4f, 0xc6, 0xdd, 0xd8, 0xbe, 0xd8, 0xbd, \
35 0x72, 0x37, 0x8c, 0xf8, 0x2f, 0x1d, 0xba, 0x2a
36 #define DRBG_TEST_GENERATED_INTERM \
37 0xdc, 0x3c, 0xf6, 0xbf, 0x5b, 0xd3, 0x41, 0x13, \
38 0x5f, 0x2c, 0x68, 0x11, 0xa1, 0x07, 0x1c, 0x87
39 # define DRBG_TEST_GENERATED \
40 0xb6, 0x18, 0x50, 0xde, 0xcf, 0xd7, 0x10, 0x6d, \
41 0x44, 0x76, 0x9a, 0x8e, 0x6e, 0x8c, 0x1a, 0xd4
42 #endif
43 #endif // _MSBN_DRBG_TEST_VECTORS_H
10.1.18 TpmAsn1.h
10.1.18.1 Introduction
This file contains the macro and structure definitions for the X509 commands and functions.
1 #ifndef _TPMASN1_H_
2 #define _TPMASN1_H_
10.1.18.2 Includes
3 #include "Tpm.h"
4 #include "OIDs.h"
10.1.18.4 Macros
37 #ifndef VERIFY
38 #define VERIFY(_X_) {if(!(_X_)) goto Error; }
39 #endif
Checks the validity of the size making sure that there is no wrap around
Marshaling works in reverse order. The offset is set to the top of the buffer and, as the buffer is filled,
offset counts down to zero. When the full thing is encoded it can be moved to the top of the buffer. This
happens when the last context is closed.
10.1.18.5 Structures
10.1.19 X509.h
10.1.19.1 Introduction
This file contains the macro and structure definitions for the X509 commands and functions.
1 #ifndef _X509_H_
2 #define _X509_H_
10.1.19.2 Includes
3 #include "Tpm.h"
4 #include "TpmASN1.h"
These defines give the order in which values appear in the TBScertificate of an x.509 certificate. These
values are used to index into an array of
9 #define ENCODED_SIZE_REF 0
10 #define VERSION_REF (ENCODED_SIZE_REF + 1)
11 #define SERIAL_NUMBER_REF (VERSION_REF + 1)
12 #define SIGNATURE_REF (SERIAL_NUMBER_REF + 1)
13 #define ISSUER_REF (SIGNATURE_REF + 1)
14 #define VALIDITY_REF (ISSUER_REF + 1)
15 #define SUBJECT_KEY_REF (VALIDITY_REF + 1)
16 #define SUBJECT_PUBLIC_KEY_REF (SUBJECT_KEY_REF + 1)
17 #define EXTENSIONS_REF (SUBJECT_PUBLIC_KEY_REF + 1)
18 #define REF_COUNT (EXTENSIONS_REF + 1)
10.1.19.4 Structures
Used to access the fields of a TBSsignature some of which are in the in_CertifyX509 structure and some
of which are in the out_CertifyX509 structure.
These values are instanced by X509_spt.c and referenced by other X509-related files. This is the DER-
encoded value for the Key Usage OID (2.5.29.15). This is the full OID, not just the numeric value
This is the DER-encoded value for the TCG-defined TPMA_OBJECT OID (2.23.133.10.1.1.1)
If a bit is SET in KEY_USAGE_SIGN is also SET in keyUsagem then the associated key has to have sign
SET.
If a bit is SET in KEY_USAGE_DECRYPT is also SET in keyUsagem then the associated key has to
have decrypt SET.
10.1.20 TpmAlgorithmDefines.h
This file contains the algorithm values from the TCG Algorithm Registry.
1 #ifndef _TPM_ALGORITHM_DEFINES_H_
2 #define _TPM_ALGORITHM_DEFINES_H_
3 #define ECC_CURVES \
4 {TPM_ECC_BN_P256, TPM_ECC_BN_P638, TPM_ECC_NIST_P192, \
5 TPM_ECC_NIST_P224, TPM_ECC_NIST_P256, TPM_ECC_NIST_P384, \
6 TPM_ECC_NIST_P521, TPM_ECC_SM2_P256}
7 #define ECC_CURVE_COUNT \
8 (ECC_BN_P256 + ECC_BN_P638 + ECC_NIST_P192 + ECC_NIST_P224 + \
9 ECC_NIST_P256 + ECC_NIST_P384 + ECC_NIST_P521 + ECC_SM2_P256)
10 #define MAX_ECC_KEY_BITS \
11 MAX(ECC_BN_P256 * 256, MAX(ECC_BN_P638 * 638, \
12 MAX(ECC_NIST_P192 * 192, MAX(ECC_NIST_P224 * 224, \
13 MAX(ECC_NIST_P256 * 256, MAX(ECC_NIST_P384 * 384, \
14 MAX(ECC_NIST_P521 * 521, MAX(ECC_SM2_P256 * 256, \
15 0))))))))
16 #define MAX_ECC_KEY_BYTES BITS_TO_BYTES(MAX_ECC_KEY_BITS)
22 #define RSA_KEY_SIZES_BITS \
23 (1024 * RSA_1024), (2048 * RSA_2048), (3072 * RSA_3072), \
24 (4096 * RSA_4096)
25 #if RSA_4096
26 # define RSA_MAX_KEY_SIZE_BITS 4096
27 #elif RSA_3072
28 # define RSA_MAX_KEY_SIZE_BITS 3072
29 #elif RSA_2048
30 # define RSA_MAX_KEY_SIZE_BITS 2048
31 #elif RSA_1024
32 # define RSA_MAX_KEY_SIZE_BITS 1024
33 #else
34 # define RSA_MAX_KEY_SIZE_BITS 0
35 #endif
36 #define MAX_RSA_KEY_BITS RSA_MAX_KEY_SIZE_BITS
37 #define MAX_RSA_KEY_BYTES ((RSA_MAX_KEY_SIZE_BITS + 7) / 8)
38 #define SHA1_DIGEST_SIZE 20
39 #define SHA1_BLOCK_SIZE 64
40 #define SHA256_DIGEST_SIZE 32
41 #define SHA256_BLOCK_SIZE 64
42 #define SHA384_DIGEST_SIZE 48
43 #define SHA384_BLOCK_SIZE 128
44 #define SHA512_DIGEST_SIZE 64
45 #define SHA512_BLOCK_SIZE 128
46 #define SM3_256_DIGEST_SIZE 32
47 #define SM3_256_BLOCK_SIZE 64
48 #define SHA3_256_DIGEST_SIZE 32
49 #define SHA3_256_BLOCK_SIZE 136
50 #define SHA3_384_DIGEST_SIZE 48
51 #define SHA3_384_BLOCK_SIZE 104
52 #define SHA3_512_DIGEST_SIZE 64
53 #define SHA3_512_BLOCK_SIZE 72
54 #define AES_KEY_SIZES_BITS \
55 (128 * AES_128), (192 * AES_192), (256 * AES_256)
56 #if AES_256
57 # define AES_MAX_KEY_SIZE_BITS 256
58 #elif AES_192
59 # define AES_MAX_KEY_SIZE_BITS 192
60 #elif AES_128
61 # define AES_MAX_KEY_SIZE_BITS 128
62 #else
63 # define AES_MAX_KEY_SIZE_BITS 0
64 #endif
65 #define MAX_AES_KEY_BITS AES_MAX_KEY_SIZE_BITS
66 #define MAX_AES_KEY_BYTES ((AES_MAX_KEY_SIZE_BITS + 7) / 8)
67 #define AES_128_BLOCK_SIZE_BYTES (AES_128 * 16)
68 #define AES_192_BLOCK_SIZE_BYTES (AES_192 * 16)
69 #define AES_256_BLOCK_SIZE_BYTES (AES_256 * 16)
70 #define AES_BLOCK_SIZES \
71 AES_128_BLOCK_SIZE_BYTES, AES_192_BLOCK_SIZE_BYTES, \
72 AES_256_BLOCK_SIZE_BYTES
73 #if ALG_AES
74 # define AES_MAX_BLOCK_SIZE 16
75 #else
76 # define AES_MAX_BLOCK_SIZE 0
77 #endif
78 #define MAX_AES_BLOCK_SIZE_BYTES AES_MAX_BLOCK_SIZE
95 #define CAMELLIA_KEY_SIZES_BITS \
96 (128 * CAMELLIA_128), (192 * CAMELLIA_192), (256 * CAMELLIA_256)
97 #if CAMELLIA_256
98 # define CAMELLIA_MAX_KEY_SIZE_BITS 256
99 #elif CAMELLIA_192
100 # define CAMELLIA_MAX_KEY_SIZE_BITS 192
101 #elif CAMELLIA_128
102 # define CAMELLIA_MAX_KEY_SIZE_BITS 128
103 #else
104 # define CAMELLIA_MAX_KEY_SIZE_BITS 0
105 #endif
106 #define MAX_CAMELLIA_KEY_BITS CAMELLIA_MAX_KEY_SIZE_BITS
107 #define MAX_CAMELLIA_KEY_BYTES ((CAMELLIA_MAX_KEY_SIZE_BITS + 7) / 8)
108 #define CAMELLIA_128_BLOCK_SIZE_BYTES (CAMELLIA_128 * 16)
109 #define CAMELLIA_192_BLOCK_SIZE_BYTES (CAMELLIA_192 * 16)
110 #define CAMELLIA_256_BLOCK_SIZE_BYTES (CAMELLIA_256 * 16)
111 #define CAMELLIA_BLOCK_SIZES \
112 CAMELLIA_128_BLOCK_SIZE_BYTES, CAMELLIA_192_BLOCK_SIZE_BYTES, \
113 CAMELLIA_256_BLOCK_SIZE_BYTES
114 #if ALG_CAMELLIA
115 # define CAMELLIA_MAX_BLOCK_SIZE 16
116 #else
117 # define CAMELLIA_MAX_BLOCK_SIZE 0
118 #endif
119 #define MAX_CAMELLIA_BLOCK_SIZE_BYTES CAMELLIA_MAX_BLOCK_SIZE
Size the array of library commands based on whether or not the array is packed (only defined commands)
or dense (having entries for unimplemented commands)
10.2 Source
10.2.1 AlgorithmTests.c
10.2.1.1 Introduction
This file contains the code to perform the various self-test functions.
NOTE: In this implementation, large local variables are made static to minimize stack usage, which is critical for stack-
constrained platforms.
1 #include "Tpm.h"
2 #define SELF_TEST_DATA
3 #if SELF_TEST
These includes pull in the data structures. They contain data definitions for the various tests.
4 #include "SelfTest.h"
5 #include "SymmetricTest.h"
6 #include "RsaTestData.h"
7 #include "EccTestData.h"
8 #include "HashTestData.h"
9 #include "KdfTestData.h"
10 #define TEST_DEFAULT_TEST_HASH(vector) \
11 if(TEST_BIT(DEFAULT_TEST_HASH, g_toTest)) \
12 TestHash(DEFAULT_TEST_HASH, vector);
22 #define CHECK_CANCELED \
23 if(_plat__IsCanceled() && toTest != &g_toTest) \
24 return TPM_RC_CANCELED;
10.2.1.3.1 Description
The hash test does a known-value HMAC using the specified hash algorithm.
10.2.1.3.2 TestHash()
25 static TPM_RC
26 TestHash(
27 TPM_ALG_ID hashAlg,
28 ALGORITHM_VECTOR *toTest
29 )
30 {
31 static TPM2B_DIGEST computed; // value computed
32 static HMAC_STATE state;
33 UINT16 digestSize;
34 const TPM2B *testDigest = NULL;
35 // TPM2B_TYPE(HMAC_BLOCK, DEFAULT_TEST_HASH_BLOCK_SIZE);
36
37 pAssert(hashAlg != ALG_NULL_VALUE);
38 switch(hashAlg)
39 {
40 #if ALG_SHA1
41 case ALG_SHA1_VALUE:
42 testDigest = &c_SHA1_digest.b;
43 break;
44 #endif
45 #if ALG_SHA256
46 case ALG_SHA256_VALUE:
47 testDigest = &c_SHA256_digest.b;
48 break;
49 #endif
50 #if ALG_SHA384
51 case ALG_SHA384_VALUE:
52 testDigest = &c_SHA384_digest.b;
53 break;
54 #endif
55 #if ALG_SHA512
56 case ALG_SHA512_VALUE:
57 testDigest = &c_SHA512_digest.b;
58 break;
59 #endif
60 #if ALG_SM3_256
61 case ALG_SM3_256_VALUE:
62 // There are currently not test vectors for SM3
63 // testDigest = &c_SM3_256_digest.b;
64 testDigest = NULL;
65 break;
66 #endif
67 default:
68 FAIL(FATAL_ERROR_INTERNAL);
69 }
70 // Clear the to-test bits
71 CLEAR_BOTH(hashAlg);
72
73 // If there is an algorithm without test vectors, then assume that things are OK.
74 if(testDigest == NULL)
75 return TPM_RC_SUCCESS;
76
77 // Set the HMAC key to twice the digest size
78 digestSize = CryptHashGetDigestSize(hashAlg);
79 CryptHmacStart(&state, hashAlg, digestSize * 2,
80 (BYTE *)c_hashTestKey.t.buffer);
81 CryptDigestUpdate(&state.hashState, 2 * CryptHashGetBlockSize(hashAlg),
82 (BYTE *)c_hashTestData.t.buffer);
83 computed.t.size = digestSize;
84 CryptHmacEnd(&state, digestSize, computed.t.buffer);
85 if((testDigest->size != computed.t.size)
86 || (memcmp(testDigest->buffer, computed.t.buffer, computed.b.size) != 0))
87 SELF_TEST_FAILURE;
88 return TPM_RC_SUCCESS;
89 }
10.2.1.4.1 MakeIv()
90 static UINT32
91 MakeIv(
92 TPM_ALG_ID mode, // IN: symmetric mode
93 UINT32 size, // IN: block size of the algorithm
94 BYTE *iv // OUT: IV to fill in
95 )
96 {
97 BYTE i;
98
99 if(mode == ALG_ECB_VALUE)
100 return 0;
101 if(mode == ALG_CTR_VALUE)
102 {
103 // The test uses an IV that has 0xff in the last byte
104 for(i = 1; i <= size; i++)
105 *iv++ = 0xff - (BYTE)(size - i);
106 }
107 else
108 {
109 for(i = 0; i < size; i++)
110 *iv++ = i;
111 }
112 return size;
113 }
10.2.1.4.2 TestSymmetricAlgorithm()
142 }
10.2.1.4.3 AllSymsAreDone()
Checks if both symmetric algorithms have been tested. This is put here so that addition of a symmetric
algorithm will be relatively easy to handle
10.2.1.4.4 AllModesAreDone()
10.2.1.4.5 TestSymmetric()
If alg is a symmetric block cipher, then all of the modes that are selected are tested. If alg is a mode, then
all algorithms of that mode are tested.
174 // Will test the algorithm for all modes and key sizes
175 CLEAR_BOTH(alg);
176
177 // A test this algorithm for all modes
178 for(index = 0; index < NUM_SYMS; index++)
179 {
180 if(c_symTestValues[index].alg == alg)
181 {
182 for(mode = TPM_SYM_MODE_FIRST;
183 mode <= TPM_SYM_MODE_LAST;
184 mode++)
185 {
186 if(TEST_BIT(mode, *toTest))
187 TestSymmetricAlgorithm(&c_symTestValues[index], mode);
188 }
189 }
190 }
191 // if all the symmetric tests are done
192 if(AllSymsAreDone(toTest))
193 {
194 // all symmetric algorithms tested so no modes should be set
195 for(alg = TPM_SYM_MODE_FIRST; alg <= TPM_SYM_MODE_LAST; alg++)
196 CLEAR_BOTH(alg);
197 }
198 }
199 else if(TPM_SYM_MODE_FIRST <= alg && alg <= TPM_SYM_MODE_LAST)
200 {
201 // Test this mode for all key sizes and algorithms
202 for(index = 0; index < NUM_SYMS; index++)
203 {
204 // The mode testing only comes into play when doing self tests
205 // by command. When doing self tests by command, the block ciphers are
206 // tested first. That means that all of their modes would have been
207 // tested for all key sizes. If there is no block cipher left to
208 // test, then clear this mode bit.
209 if(!TEST_BIT(ALG_AES_VALUE, *toTest)
210 && !TEST_BIT(ALG_SM4_VALUE, *toTest))
211 {
212 CLEAR_BOTH(alg);
213 }
214 else
215 {
216 for(index = 0; index < NUM_SYMS; index++)
217 {
218 if(TEST_BIT(c_symTestValues[index].alg, *toTest))
219 TestSymmetricAlgorithm(&c_symTestValues[index], alg);
220 }
221 // have tested this mode for all algorithms
222 CLEAR_BOTH(alg);
223 }
224 }
225 if(AllModesAreDone(toTest))
226 {
227 CLEAR_BOTH(ALG_AES_VALUE);
228 CLEAR_BOTH(ALG_SM4_VALUE);
229 }
230 }
231 else
232 pAssert(alg == 0 && alg != 0);
233 return TPM_RC_SUCCESS;
234 }
10.2.1.5.1 Introduction
The tests are for public key only operations and for private key operations. Signature verification and
encryption are public key operations. They are tested by using a KVT. For signature verification, this
means that a known good signature is checked by CryptRsaValidateSignature(). If it fails, then the TPM
enters failure mode. For encryption, the TPM encrypts known values using the selected scheme and
checks that the returned value matches the expected value.
For private key operations, a full scheme check is used. For a signing key, a known key is used to sign a
known message. Then that signature is verified. since the signature may involve use of random values,
the signature will be different each time and we can't always check that the signature matches a known
value. The same technique is used for decryption (RSADP/RSAEP).
When an operation uses the public key and the verification has not been tested, the TPM will do a KVT.
The test for the signing algorithm is built into the call for the algorithm
10.2.1.5.2 RsaKeyInitialize()
The test key is defined by a public modulus and a private prime. The TPM's RSA code computes the
second prime and the private exponent.
10.2.1.5.3 TestRsaEncryptDecrypt()
These tests are for a public key encryption that uses a random value.
271 // This is an encryption scheme using the private key without any encoding.
272 memcpy(testInput.t.buffer, c_RsaTestValue, sizeof(c_RsaTestValue));
273 testInput.t.size = sizeof(c_RsaTestValue);
274 if(TPM_RC_SUCCESS != CryptRsaEncrypt(&testOutput, &testInput.b,
275 &testObject, &rsaScheme, NULL, NULL))
276 SELF_TEST_FAILURE;
277 if(!MemoryEqual(testOutput.t.buffer, c_RsaepKvt.buffer, c_RsaepKvt.size))
278 SELF_TEST_FAILURE;
279 MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
280 if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
281 &testObject, &rsaScheme, NULL))
282 SELF_TEST_FAILURE;
283 if(!MemoryEqual(testOutput.t.buffer, c_RsaTestValue,
284 sizeof(c_RsaTestValue)))
285 SELF_TEST_FAILURE;
286 }
287 else
288 {
289 // ALG_RSAES_VALUE:
290 // This is an decryption scheme using padding according to
291 // PKCS#1v2.1, 7.2. This padding uses random bits. To test a public
292 // key encryption that uses random data, encrypt a value and then
293 // decrypt the value and see that we get the encrypted data back.
294 // The hash is not used by this encryption so it can be TMP_ALG_NULL
295
296 // ALG_OAEP_VALUE:
297 // This is also an decryption scheme and it also uses a
298 // pseudo-random
299 // value. However, this also uses a hash algorithm. So, we may need
300 // to test that algorithm before use.
301 if(scheme == ALG_OAEP_VALUE)
302 {
303 TEST_DEFAULT_TEST_HASH(toTest);
304 kvtValue = &c_OaepKvt;
305 testLabel = OAEP_TEST_STRING;
306 }
307 else if(scheme == ALG_RSAES_VALUE)
308 {
309 kvtValue = &c_RsaesKvt;
310 testLabel = NULL;
311 }
312 else
313 SELF_TEST_FAILURE;
314 // Only use a digest-size portion of the test value
315 memcpy(testInput.t.buffer, c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE);
316 testInput.t.size = DEFAULT_TEST_DIGEST_SIZE;
317
318 // See if the encryption works
319 if(TPM_RC_SUCCESS != CryptRsaEncrypt(&testOutput, &testInput.b,
320 &testObject, &rsaScheme, testLabel,
321 NULL))
322 SELF_TEST_FAILURE;
323 MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
324 // see if we can decrypt this value and get the original data back
325 if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
326 &testObject, &rsaScheme, testLabel))
327 SELF_TEST_FAILURE;
328 // See if the results compare
329 if(testOutput.t.size != DEFAULT_TEST_DIGEST_SIZE
330 || !MemoryEqual(testOutput.t.buffer, c_RsaTestValue,
331 DEFAULT_TEST_DIGEST_SIZE))
332 SELF_TEST_FAILURE;
333 // Now check that the decryption works on a known value
334 MemoryCopy2B(&testInput.b, (P2B)kvtValue,
335 sizeof(testInput.t.buffer));
336 if(TPM_RC_SUCCESS != CryptRsaDecrypt(&testOutput.b, &testInput.b,
10.2.1.5.4 TestRsaSignAndVerify()
This function does the testing of the RSA sign and verification functions. This test does a KVT.
10.2.1.5.5 TestRSA()
Function uses the provided vector to indicate which tests to run. It will clear the vector after each test is
run and also clear g_toTest
454 break;
455 default:
456 SELF_TEST_FAILURE;
457 }
458 return result;
459 }
460 #endif // ALG_RSA
10.2.1.6.1 LoadEccParameter()
10.2.1.6.2 LoadEccPoint()
10.2.1.6.3 TestECDH()
10.2.1.6.4 TestEccSignAndVerify()
10.2.1.6.5 TestKDFa()
10.2.1.6.6 TestEcc()
619 }
620 break;
621 case ALG_ECDSA_VALUE:
622 case ALG_ECSCHNORR_VALUE:
623 case ALG_SM2_VALUE:
624 result = TestEccSignAndVerify(alg, toTest);
625 break;
626 default:
627 SELF_TEST_FAILURE;
628 break;
629 }
630 return result;
631 }
632 #endif // ALG_ECC
10.2.1.6.7 TestAlgorithm()
Dispatches to the correct test function for the algorithm or gets a list of testable algorithms.
If toTest is not NULL, then the test decisions are based on the algorithm selections in toTest. Otherwise,
g_toTest is used. When bits are clear in g_toTest they will also be cleared toTest.
If there doesn't happen to be a test for the algorithm, its associated bit is quietly cleared.
If alg is zero (TPM_ALG_ERROR), then the toTest vector is cleared of any bits for which there is no test
(i.e. no tests are actually run but the vector is cleared).
NOTE: toTest will only ever have bits set for implemented algorithms but alg can be anything.
633 LIB_EXPORT
634 TPM_RC
635 TestAlgorithm(
636 TPM_ALG_ID alg,
637 ALGORITHM_VECTOR *toTest
638 )
639 {
640 TPM_ALG_ID first = (alg == ALG_ERROR_VALUE) ? ALG_FIRST_VALUE : alg;
641 TPM_ALG_ID last = (alg == ALG_ERROR_VALUE) ? ALG_LAST_VALUE : alg;
642 BOOL doTest = (alg != ALG_ERROR_VALUE);
643 TPM_RC result = TPM_RC_SUCCESS;
644
645 if(toTest == NULL)
646 toTest = &g_toTest;
647
648 // This is kind of strange. This function will either run a test of the selected
649 // algorithm or just clear a bit if there is no test for the algorithm. So,
650 // either this loop will be executed once for the selected algorithm or once for
651 // each of the possible algorithms. If it is executed more than once ('alg' ==
652 // ALG_ERROR), then no test will be run but bits will be cleared for
653 // unimplemented algorithms. This was done this way so that there is only one
654 // case statement with all of the algorithms. It was easier to have one case
655 // statement than to have multiple ones to manage whenever an algorithm ID is
656 // added.
657 for(alg = first; (alg <= last); alg++)
658 {
659 // if 'alg' was TPM_ALG_ERROR, then we will be cycling through
660 // values, some of which may not be implemented. If the bit in toTest
661 // happens to be set, then we could either generated an assert, or just
662 // silently CLEAR it. Decided to just clear.
663 if(!TEST_BIT(alg, g_implementedAlgorithms))
664 {
665 CLEAR_BIT(alg, *toTest);
666 continue;
667 }
668 // Process whatever is left.
669 // NOTE: since this switch will only be called if the algorithm is
670 // implemented, it is not necessary to modify this list except to comment
671 // out the algorithms for which there is no test
672 switch(alg)
673 {
674 // Symmetric block ciphers
675 #if ALG_AES
676 case ALG_AES_VALUE:
677 #endif // ALG_AES
678 #if ALG_SM4
679 // if SM4 is implemented, its test is like other block ciphers but there
680 // aren't any test vectors for it yet
681 // case ALG_SM4_VALUE:
682 #endif // ALG_SM4
683 #if ALG_CAMELLIA
684 // no test vectors for camellia
685 // case ALG_CAMELLIA_VALUE:
686 #endif
687 // Symmetric modes
688 #if !ALG_CFB
689 # error CFB is required in all TPM implementations
690 #endif // !ALG_CFB
691 case ALG_CFB_VALUE:
692 if(doTest)
693 result = TestSymmetric(alg, toTest);
694 break;
695 #if ALG_CTR
696 case ALG_CTR_VALUE:
697 #endif // ALG_CRT
698 #if ALG_OFB
699 case ALG_OFB_VALUE:
700 #endif // ALG_OFB
701 #if ALG_CBC
702 case ALG_CBC_VALUE:
703 #endif // ALG_CBC
704 #if ALG_ECB
705 case ALG_ECB_VALUE:
706 #endif
707 if(doTest)
708 result = TestSymmetric(alg, toTest);
709 else
710 // If doing the initialization of g_toTest vector, only need
711 // to test one of the modes for the symmetric algorithms. If
712 // initializing for a SelfTest(FULL_TEST), allow all the modes.
713 if(toTest == &g_toTest)
714 CLEAR_BIT(alg, *toTest);
715 break;
716 #if !ALG_HMAC
717 # error HMAC is required in all TPM implementations
718 #endif
719 case ALG_HMAC_VALUE:
720 // Clear the bit that indicates that HMAC is required because
721 // HMAC is used as the basic test for all hash algorithms.
722 CLEAR_BOTH(alg);
723 // Testing HMAC means test the default hash
724 if(doTest)
725 TestHash(DEFAULT_TEST_HASH, toTest);
726 else
727 // If not testing, then indicate that the hash needs to be
728 // tested because this uses HMAC
729 SET_BOTH(DEFAULT_TEST_HASH);
730 break;
731 #if ALG_SHA1
732 case ALG_SHA1_VALUE:
733 #endif // ALG_SHA1
734 #if ALG_SHA256
735 case ALG_SHA256_VALUE:
736 #endif // ALG_SHA256
737 #if ALG_SHA384
738 case ALG_SHA384_VALUE:
739 #endif // ALG_SHA384
740 #if ALG_SHA512
741 case ALG_SHA512_VALUE:
742 #endif // ALG_SHA512
743 // if SM3 is implemented its test is like any other hash, but there
744 // aren't any test vectors yet.
745 #if ALG_SM3_256
746 // case ALG_SM3_256_VALUE:
747 #endif // ALG_SM3_256
748 if(doTest)
749 result = TestHash(alg, toTest);
750 break;
751 // RSA-dependent
752 #if ALG_RSA
753 case ALG_RSA_VALUE:
754 CLEAR_BOTH(alg);
755 if(doTest)
756 result = TestRsa(ALG_NULL_VALUE, toTest);
757 else
758 SET_BOTH(ALG_NULL_VALUE);
759 break;
760 case ALG_RSASSA_VALUE:
761 case ALG_RSAES_VALUE:
762 case ALG_RSAPSS_VALUE:
763 case ALG_OAEP_VALUE:
764 case ALG_NULL_VALUE: // used or RSADP
765 if(doTest)
766 result = TestRsa(alg, toTest);
767 break;
768 #endif // ALG_RSA
769 #if ALG_KDF1_SP800_108
770 case ALG_KDF1_SP800_108_VALUE:
771 if(doTest)
772 result = TestKDFa(toTest);
773 break;
774 #endif // ALG_KDF1_SP800_108
775 #if ALG_ECC
776 // ECC dependent but no tests
777 // case ALG_ECDAA_VALUE:
778 // case ALG_ECMQV_VALUE:
779 // case ALG_KDF1_SP800_56a_VALUE:
780 // case ALG_KDF2_VALUE:
781 // case ALG_MGF1_VALUE:
782 case ALG_ECC_VALUE:
783 CLEAR_BOTH(alg);
784 if(doTest)
785 result = TestEcc(ALG_ECDH_VALUE, toTest);
786 else
787 SET_BOTH(ALG_ECDH_VALUE);
788 break;
789 case ALG_ECDSA_VALUE:
790 case ALG_ECDH_VALUE:
791 case ALG_ECSCHNORR_VALUE:
792 // case ALG_SM2_VALUE:
793 if(doTest)
794 result = TestEcc(alg, toTest);
795 break;
10.2.2 BnConvert.c
10.2.2.1 Introduction
This file contains the basic conversion functions that will convert TPM2B to/from the internal format. The
internal format is a bigNum,
10.2.2.2 Includes
1 #include "Tpm.h"
10.2.2.3 Functions
10.2.2.3.1 BnFromBytes()
This function will convert a big-endian byte array to the internal number format. If bn is NULL, then the
output is NULL. If bytes is null or the required size is 0, then the output is set to zero
2 LIB_EXPORT bigNum
3 BnFromBytes(
4 bigNum bn,
5 const BYTE *bytes,
6 NUMBYTES nBytes
7 )
8 {
9 const BYTE *pFrom; // 'p' points to the least significant bytes of source
10 BYTE *pTo; // points to least significant bytes of destination
11 crypt_uword_t size;
12 //
13
14 size = (bytes != NULL) ? BYTES_TO_CRYPT_WORDS(nBytes) : 0;
15
16 // If nothing in, nothing out
17 if(bn == NULL)
18 return NULL;
19
20 // make sure things fit
21 pAssert(BnGetAllocated(bn) >= size);
22
23 if(size > 0)
24 {
25 // Clear the topmost word in case it is not filled with data
26 bn->d[size - 1] = 0;
27 // Moving the input bytes from the end of the list (LSB) end
28 pFrom = bytes + nBytes - 1;
29 // To the LS0 of the LSW of the bigNum.
30 pTo = (BYTE *)bn->d;
31 for(; nBytes != 0; nBytes--)
32 *pTo++ = *pFrom--;
33 // For a little-endian machine, the conversion is a straight byte
34 // reversal. For a big-endian machine, we have to put the words in
35 // big-endian byte order
36 #if BIG_ENDIAN_TPM
37 {
38 crypt_word_t t;
39 for(t = (crypt_word_t)size - 1; t >= 0; t--)
40 bn->d[t] = SWAP_CRYPT_WORD(bn->d[t]);
41 }
42 #endif
43 }
44 BnSetTop(bn, size);
45 return bn;
46 }
10.2.2.3.2 BnFrom2B()
Convert an TPM2B to a BIG_NUM. If the input value does not exist, or the output does not exist, or the
input will not fit into the output the function returns NULL
47 LIB_EXPORT bigNum
48 BnFrom2B(
49 bigNum bn, // OUT:
50 const TPM2B *a2B // IN: number to convert
51 )
52 {
53 if(a2B != NULL)
54 return BnFromBytes(bn, a2B->buffer, a2B->size);
55 // Make sure that the number has an initialized value rather than whatever
56 // was there before
57 BnSetTop(bn, 0); // Function accepts NULL
58 return NULL;
59 }
10.2.2.3.3 BnFromHex()
60 LIB_EXPORT bigNum
61 BnFromHex(
62 bigNum bn, // OUT:
63 const char *hex // IN:
64 )
65 {
66 #define FromHex(a) ((a) - (((a) > 'a') ? ('a' + 10) \
67 : ((a) > 'A') ? ('A' - 10) : '0'))
68 unsigned i;
69 unsigned wordCount;
70 const char *p;
71 BYTE *d = (BYTE *)&(bn->d[0]);
72 //
73 pAssert(bn && hex);
74 i = (unsigned)strlen(hex);
75 wordCount = BYTES_TO_CRYPT_WORDS((i + 1) / 2);
76 if((i == 0) || (wordCount >= BnGetAllocated(bn)))
77 BnSetWord(bn, 0);
78 else
79 {
80 bn->d[wordCount - 1] = 0;
81 p = hex + i - 1;
82 for(;i > 1; i -= 2)
83 {
84 BYTE a;
85 a = FromHex(*p);
86 p--;
87 *d++ = a + (FromHex(*p) << 4);
88 p--;
89 }
90 if(i == 1)
91 *d = FromHex(*p);
92 }
93 #if !BIG_ENDIAN_TPM
94 for(i = 0; i < wordCount; i++)
95 bn->d[i] = SWAP_CRYPT_WORD(bn->d[i]);
96 #endif // BIG_ENDIAN_TPM
97 BnSetTop(bn, wordCount);
98 return bn;
99 }
10.2.2.3.4 BnToBytes()
This function converts a BIG_NUM to a byte array. It converts the bigNum to a big-endian byte string and
sets size to the normalized value. If size is an input 0, then the receiving buffer is guaranteed to be large
enough for the result and the size will be set to the size required for bigNum (leading zeros suppressed).
The conversion for a little-endian machine simply requires that all significant bytes of the bigNum be
reversed. For a big-endian machine, rather than unpack each word individually, the bigNum is converted
to little-endian words, copied, and then converted back to big-endian.
149 // Move the most significant byte at the end of the BigNum to the next most
150 // significant byte position of the 2B and repeat for all significant bytes.
151 for(; requiredSize > 0; requiredSize--)
152 *pTo++ = *pFrom--;
153 }
154 return TRUE;
155 }
10.2.2.3.5 BnTo2B()
Function to convert a BIG_NUM to TPM2B. The TPM2B size is set to the requested size which may
require padding. If size is non-zero and less than required by the value in bn then an error is returned. If
size is zero, then the TPM2B is assumed to be large enough for the data and a2b->size will be adjusted
accordingly.
10.2.2.3.6 BnPointFrom2B()
Function to create a BIG_POINT structure from a 2B point. A point is going to be two ECC values in the
same buffer. The values are going to be the size of the modulus. They are in modular form.
10.2.2.3.7 BnPointTo2B()
EC key size used in an implementation. The presumption is that the TPMS_ECC_POINT is large enough
to hold 2 TPM2B values, each as large as a MAX_ECC_PARAMETER_BYTES
10.2.3 BnMath.c
10.2.3.1 Introduction
The simulator code uses the canonical form whenever possible in order to make the code in Part 3 more
accessible. The canonical data formats are simple and not well suited for complex big number
computations. When operating on big numbers, the data format is changed for easier manipulation. The
format is native words in little-endian format. As the magnitude of the number decreases, the length of the
array containing the number decreases but the starting address doesn't change.
The functions in this file perform simple operations on these big numbers. Only the more complex
operations are passed to the underlying support library. Although the support library would have most of
these functions, the interface code to convert the format for the values is greater than the size of the code
to implement the functions here. So, rather than incur the overhead of conversion, they are done here.
If an implementer would prefer, the underlying library can be used simply by making code substitutions
here.
NOTE: There is an intention to continue to augment these functions so that there would be no need to use an external
big number library.
Many of these functions have no error returns and will always return TRUE. This is to allow them to be
used in guarded sequences. That is: OK = OK || BnSomething(s); where the BnSomething() function
should not be called if OK isn't true.
10.2.3.2 Includes
1 #include "Tpm.h"
10.2.3.2.1 CarryProp()
Propagate a carry
41 static int
42 CarryProp(
43 crypt_uword_t *result,
44 const crypt_uword_t *op,
45 int count,
46 int carry
47 )
48 {
49 for(; count; count--)
50 carry = ((*result++ = *op++ + carry) == 0) & carry;
51 return carry;
52 }
53 static void
54 CarryResolve(
55 bigNum result,
56 int stop,
57 int carry
58 )
59 {
60 if(carry)
61 {
62 pAssert((unsigned)stop < result->allocated);
63 result->d[stop++] = 1;
64 }
65 BnSetTop(result, stop);
66 }
10.2.3.2.2 BnAdd()
This function adds two bigNum values. This function always returns TRUE.
67 LIB_EXPORT BOOL
68 BnAdd(
69 bigNum result,
70 bigConst op1,
71 bigConst op2
72 )
73 {
74 crypt_uword_t stop;
75 int carry;
76 const bignum_t *n1 = op1;
77 const bignum_t *n2 = op2;
78
79 //
80 if(n2->size > n1->size)
81 {
82 n1 = op2;
83 n2 = op1;
84 }
10.2.3.2.3 BnAddWord()
This function adds a word value to a bigNum. This function always returns TRUE.
93 LIB_EXPORT BOOL
94 BnAddWord(
95 bigNum result,
96 bigConst op,
97 crypt_uword_t word
98 )
99 {
100 int carry;
101 //
102 carry = (result->d[0] = op->d[0] + word) < word;
103 carry = CarryProp(&result->d[1], &op->d[1], (int)(op->size - 1), carry);
104 CarryResolve(result, (int)op->size, carry);
105 return TRUE;
106 }
10.2.3.2.4 SubSame()
This function subtracts two values that have the same size.
10.2.3.2.5 BorrowProp()
This propagates a borrow. If borrow is true when the end of the array is reached, then it means that op2
was larger than op1 and we don't handle that case so an assert is generated. This design choice was
made because our only bigNum computations are on large positive numbers (primes) or on fields.
Propagate a borrow.
10.2.3.2.6 BnSub()
This function does subtraction of two bigNum values and returns result = op1 - op2 when op1 is greater
than op2. If op2 is greater than op1, then a fault is generated. This function always returns TRUE.
10.2.3.2.7 BnSubWord()
This function subtracts a word value from a bigNum. This function always returns TRUE.
10.2.3.2.8 BnUnsignedCmp()
This function performs a comparison of op1 to op2. The compare is approximately constant time if the
size of the values used in the compare is consistent across calls (from the same line in the calling code).
10.2.3.2.9 BnUnsignedCmpWord()
10.2.3.2.10 BnModWord()
This function does modular division of a big number when the modulus is a word value.
10.2.3.2.11 Msb()
This function returns the bit number of the most significant bit of a crypt_uword_t. The number for the
least significant bit of any bigNum value is 0. The maximum return value is RADIX_BITS - 1,
10.2.3.2.12 BnMsb()
249 {
250 // If the value is NULL, or the size is zero then treat as zero and return -1
251 if(bn != NULL && bn->size > 0)
252 {
253 int retVal = Msb(bn->d[bn->size - 1]);
254 retVal += (int)(bn->size - 1) * RADIX_BITS;
255 return retVal;
256 }
257 else
258 return -1;
259 }
10.2.3.2.13 BnSizeInBits()
This function returns the number of bits required to hold a number. It is one greater than the Msb.
10.2.3.2.14 BnSetWord()
10.2.3.2.15 BnSetBit()
This function will SET a bit in a bigNum. Bit 0 is the least-significant bit in the 0th digit_t. The function
always return TRUE
10.2.3.2.16 BnTestBit()
This function is used to check to see if a bit is SET in a bignum_t. The 0th bit is the LSb of d[0].
10.2.3.2.17 BnMaskBits()
This function is used to mask off high order bits of a big number. The returned value will have no more
than maskBit bits set.
NOTE: There is a requirement that unused words of a bignum_t are set to zero.
10.2.3.2.18 BnShiftRight()
This function will shift a bigNum to the right by the shiftAmount. This function always returns TRUE.
10.2.3.2.19 BnGetRandomBits()
This function gets random bits for use in various places. To make sure that the number is generated in a
portable format, it is created as a TPM2B and then converted to the internal format.
One consequence of the generation scheme is that, if the number of bits requested is not a multiple of 8,
then the high-order bits are set to zero. This would come into play when generating a 521-bit ECC key. A
66-byte (528-bit) value is generated an the high order 7 bits are masked off (CLEAR).
10.2.3.2.20 BnGenerateRandomInRange()
This function is used to generate a random number r in the range 1 <= r < limit. The function gets a
random number of bits that is the size of limit. There is some some probability that the returned number is
going to be greater than or equal to the limit. If it is, try again. There is no more than 50% chance that the
next number is also greater, so try again. We keep trying until we get a value that meets the criteria.
Since limit is very often a number with a LOT of high order ones, this rarely would need a second try.
10.2.4 BnMemory.c
10.2.4.1 Introduction
This file contains the memory setup functions used by the bigNum functions in CryptoEngine()
10.2.4.2 Includes
1 #include "Tpm.h"
10.2.4.3 Functions
10.2.4.3.1 BnSetTop()
This function is used when the size of a bignum_t is changed. It makes sure that the unused words are
set to zero and that any significant words of zeros are eliminated from the used size indicator.
2 LIB_EXPORT bigNum
3 BnSetTop(
4 bigNum bn, // IN/OUT: number to clean
5 crypt_uword_t top // IN: the new top
6 )
7 {
8 if(bn != NULL)
9 {
10 pAssert(top <= bn->allocated);
11 // If forcing the size to be decreased, make sure that the words being
12 // discarded are being set to 0
13 while(bn->size > top)
14 bn->d[--bn->size] = 0;
15 bn->size = top;
16 // Now make sure that the words that are left are 'normalized' (no high-order
17 // words of zero.
18 while((bn->size > 0) && (bn->d[bn->size - 1] == 0))
19 bn->size -= 1;
20 }
21 return bn;
22 }
10.2.4.3.2 BnClearTop()
This function will make sure that all unused words are zero.
23 LIB_EXPORT bigNum
24 BnClearTop(
25 bigNum bn
26 )
27 {
28 crypt_uword_t i;
29 //
30 if(bn != NULL)
31 {
32 for(i = bn->size; i < bn->allocated; i++)
33 bn->d[i] = 0;
34 while((bn->size > 0) && (bn->d[bn->size] == 0))
35 bn->size -= 1;
36 }
37 return bn;
38 }
10.2.4.3.3 BnInitializeWord()
This function is used to initialize an allocated bigNum with a word value. The bigNum does not have to be
allocated with a single word.
39 LIB_EXPORT bigNum
40 BnInitializeWord(
41 bigNum bn, // IN:
42 crypt_uword_t allocated, // IN:
43 crypt_uword_t word // IN:
44 )
45 {
46 bn->allocated = allocated;
47 bn->size = (word != 0);
48 bn->d[0] = word;
49 while(allocated > 1)
50 bn->d[--allocated] = 0;
51 return bn;
52 }
10.2.4.3.4 BnInit()
This function initializes a stack allocated bignum_t. It initializes allocated and size and zeros the words of
d.
53 LIB_EXPORT bigNum
54 BnInit(
55 bigNum bn,
56 crypt_uword_t allocated
57 )
58 {
59 if(bn != NULL)
60 {
61 bn->allocated = allocated;
62 bn->size = 0;
63 while(allocated != 0)
64 bn->d[--allocated] = 0;
65 }
66 return bn;
67 }
10.2.4.3.5 BnCopy()
Function to copy a bignum_t. If the output is NULL, then nothing happens. If the input is NULL, the output
is set to zero.
68 LIB_EXPORT BOOL
69 BnCopy(
70 bigNum out,
71 bigConst in
72 )
73 {
74 if(in == out)
75 BnSetTop(out, BnGetSize(out));
76 else if(out != NULL)
77 {
78 if(in != NULL)
79 {
80 unsigned int i;
81 pAssert(BnGetAllocated(out) >= BnGetSize(in));
82 for(i = 0; i < BnGetSize(in); i++)
83 out->d[i] = in->d[i];
84 BnSetTop(out, BnGetSize(in));
85 }
86 else
87 BnSetTop(out, 0);
88 }
89 return TRUE;
90 }
91 #if ALG_ECC
10.2.4.3.6 BnPointCopy()
92 LIB_EXPORT BOOL
93 BnPointCopy(
94 bigPoint pOut,
95 pointConst pIn
96 )
97 {
98 return BnCopy(pOut->x, pIn->x)
99 && BnCopy(pOut->y, pIn->y)
100 && BnCopy(pOut->z, pIn->z);
101 }
10.2.4.3.7 BnInitializePoint()
This function is used to initialize a point structure with the addresses of the coordinates.
10.2.5 CryptCmac.c
10.2.5.1 Introduction
This file contains the implementation of the message authentication codes based on a symmetric block
cipher. These functions only use the single block encryption functions of the selected symmetric
cryptographic library.
1 #define _CRYPT_HASH_C_
2 #include "Tpm.h"
3 #include "CryptSym.h"
4 #if ALG_CMAC
10.2.5.3 Functions
10.2.5.3.1 CryptCmacStart()
This is the function to start the CMAC sequence operation. It initializes the dispatch functions for the data
and end operations for CMAC and initializes the parameters that are used for the processing of data,
including the key, key size and block cipher algorithm.
5 UINT16
6 CryptCmacStart(
7 SMAC_STATE *state,
8 TPMU_PUBLIC_PARMS *keyParms,
9 TPM_ALG_ID macAlg,
10 TPM2B *key
11 )
12 {
13 tpmCmacState_t *cState = &state->state.cmac;
14 TPMT_SYM_DEF_OBJECT *def = &keyParms->symDetail.sym;
15 //
16 if(macAlg != TPM_ALG_CMAC)
17 return 0;
18 // set up the encryption algorithm and parameters
19 cState->symAlg = def->algorithm;
20 cState->keySizeBits = def->keyBits.sym;
21 cState->iv.t.size = CryptGetSymmetricBlockSize(def->algorithm,
22 def->keyBits.sym);
23 MemoryCopy2B(&cState->symKey.b, key, sizeof(cState->symKey.t.buffer));
24
25 // Set up the dispatch methods for the CMAC
26 state->smacMethods.data = CryptCmacData;
27 state->smacMethods.end = CryptCmacEnd;
28 return cState->iv.t.size;
29 }
10.2.5.3.2 CryptCmacData()
This function is used to add data to the CMAC sequence computation. The function will XOR new data
into the IV. If the buffer is full, and there is additional input data, the data is encrypted into the IV buffer,
the new data is then XOR into the IV. When the data runs out, the function returns without encrypting
even if the buffer is full. The last data block of a sequence will not be encrypted until the call to
CryptCmacEnd(). This is to allow the proper subkey to be computed and applied before the last block is
encrypted.
30 void
31 CryptCmacData(
32 SMAC_STATES *state,
33 UINT32 size,
34 const BYTE *buffer
35 )
36 {
37 tpmCmacState_t *cmacState = &state->cmac;
38 TPM_ALG_ID algorithm = cmacState->symAlg;
39 BYTE *key = cmacState->symKey.t.buffer;
40 UINT16 keySizeInBits = cmacState->keySizeBits;
41 tpmCryptKeySchedule_t keySchedule;
42 TpmCryptSetSymKeyCall_t encrypt;
43 //
44 SELECT(ENCRYPT);
45 while(size > 0)
46 {
47 if(cmacState->bcount == cmacState->iv.t.size)
48 {
49 ENCRYPT(&keySchedule, cmacState->iv.t.buffer, cmacState->iv.t.buffer);
50 cmacState->bcount = 0;
51 }
52 for(;(size > 0) && (cmacState->bcount < cmacState->iv.t.size);
53 size--, cmacState->bcount++)
54 {
55 cmacState->iv.t.buffer[cmacState->bcount] ^= *buffer++;
56 }
57 }
58 }
10.2.5.3.3 CryptCmacEnd()
This is the completion function for the CMAC. It does padding, if needed, and selects the subkey to be
applied before the last block is encrypted.
59 UINT16
60 CryptCmacEnd(
61 SMAC_STATES *state,
62 UINT32 outSize,
63 BYTE *outBuffer
64 )
65 {
66 tpmCmacState_t *cState = &state->cmac;
67 // Need to set algorithm, key, and keySizeInBits in the local context so that
68 // the SELECT and ENCRYPT macros will work here
69 TPM_ALG_ID algorithm = cState->symAlg;
70 BYTE *key = cState->symKey.t.buffer;
71 UINT16 keySizeInBits = cState->keySizeBits;
72 tpmCryptKeySchedule_t keySchedule;
73 TpmCryptSetSymKeyCall_t encrypt;
74 TPM2B_IV subkey = {{0, {0}}};
75 BOOL xorVal;
76 UINT16 i;
77
78 subkey.t.size = cState->iv.t.size;
79 // Encrypt a block of zero
80 SELECT(ENCRYPT);
81 ENCRYPT(&keySchedule, subkey.t.buffer, subkey.t.buffer);
82
83 // shift left by 1 and XOR with 0x0...87 if the MSb was 0
84 xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87;
85 ShiftLeft(&subkey.b);
86 subkey.t.buffer[subkey.t.size - 1] ^= xorVal;
87 // this is a sanity check to make sure that the algorithm is working properly.
10.2.6 CryptUtil.c
10.2.6.1 Introduction
This module contains the interfaces to the CryptoEngine() and provides miscellaneous cryptographic
functions in support of the TPM.
10.2.6.2 Includes
1 #include "Tpm.h"
10.2.6.3.1 CryptHmacSign()
Sign a digest using an HMAC key. This an HMAC of a digest, not an HMAC of a message.
2 static TPM_RC
3 CryptHmacSign(
4 TPMT_SIGNATURE *signature, // OUT: signature
5 OBJECT *signKey, // IN: HMAC key sign the hash
6 TPM2B_DIGEST *hashData // IN: hash to be signed
7 )
8 {
9 HMAC_STATE hmacState;
10 UINT32 digestSize;
11
12 digestSize = CryptHmacStart2B(&hmacState, signature->signature.any.hashAlg,
13 &signKey->sensitive.sensitive.bits.b);
14 CryptDigestUpdate2B(&hmacState.hashState, &hashData->b);
15 CryptHmacEnd(&hmacState, digestSize,
16 (BYTE *)&signature->signature.hmac.digest);
17 return TPM_RC_SUCCESS;
18 }
10.2.6.3.2 CryptHMACVerifySignature()
This function will verify a signature signed by a HMAC key. Note that a caller needs to prepare signature
with the signature algorithm (TPM_ALG_HMAC) and the hash algorithm to use. This function then builds
a signature of that type.
19 static TPM_RC
20 CryptHMACVerifySignature(
21 OBJECT *signKey, // IN: HMAC key signed the hash
22 TPM2B_DIGEST *hashData, // IN: digest being verified
23 TPMT_SIGNATURE *signature // IN: signature to be verified
24 )
25 {
26 TPMT_SIGNATURE test;
27 TPMT_KEYEDHASH_SCHEME *keyScheme =
28 &signKey->publicArea.parameters.keyedHashDetail.scheme;
29 //
30 if((signature->sigAlg != ALG_HMAC_VALUE)
31 || (signature->signature.hmac.hashAlg == ALG_NULL_VALUE))
32 return TPM_RC_SCHEME;
33 // This check is not really needed for verification purposes. However, it does
34 // prevent someone from trying to validate a signature using a weaker hash
35 // algorithm than otherwise allowed by the key. That is, a key with a scheme
36 // other than TMP_ALG_NULL can only be used to validate signatures that have
37 // a matching scheme.
38 if((keyScheme->scheme != ALG_NULL_VALUE)
39 && ((keyScheme->scheme != signature->sigAlg)
40 || (keyScheme->details.hmac.hashAlg
41 != signature->signature.any.hashAlg)))
42 return TPM_RC_SIGNATURE;
43 test.sigAlg = signature->sigAlg;
44 test.signature.hmac.hashAlg = signature->signature.hmac.hashAlg;
45
46 CryptHmacSign(&test, signKey, hashData);
47
48 // Compare digest
49 if(!MemoryEqual(&test.signature.hmac.digest,
50 &signature->signature.hmac.digest,
51 CryptHashGetDigestSize(signature->signature.any.hashAlg)))
52 return TPM_RC_SIGNATURE;
53
54 return TPM_RC_SUCCESS;
55 }
10.2.6.3.3 CryptGenerateKeyedHash()
56 static TPM_RC
57 CryptGenerateKeyedHash(
58 TPMT_PUBLIC *publicArea, // IN/OUT: the public area template
59 // for the new key.
60 TPMT_SENSITIVE *sensitive, // OUT: sensitive area
61 TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation data
62 RAND_STATE *rand // IN: "entropy" source
63 )
64 {
65 TPMT_KEYEDHASH_SCHEME *scheme;
66 TPM_ALG_ID hashAlg;
67 UINT16 digestSize;
68
69 scheme = &publicArea->parameters.keyedHashDetail.scheme;
70
71 if(publicArea->type != ALG_KEYEDHASH_VALUE)
72 return TPM_RC_FAILURE;
73
74 // Pick the limiting hash algorithm
75 if(scheme->scheme == ALG_NULL_VALUE)
76 hashAlg = publicArea->nameAlg;
77 else if(scheme->scheme == ALG_XOR_VALUE)
78 hashAlg = scheme->details.xor.hashAlg;
79 else
80 hashAlg = scheme->details.hmac.hashAlg;
81 digestSize = CryptHashGetDigestSize(hashAlg);
82
83 // if this is a signing or a decryption key, then the limit
84 // for the data size is the block size of the hash. This limit
85 // is set because larger values have lower entropy because of the
86 // HMAC function. The lower limit is 1/2 the size of the digest
87 //
88 //If the user provided the key, check that it is a proper size
89 if(sensitiveCreate->data.t.size != 0)
90 {
91 if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
92 || IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
93 {
94 if(sensitiveCreate->data.t.size > CryptHashGetBlockSize(hashAlg))
95 return TPM_RC_SIZE;
96 #if 0 // May make this a FIPS-mode requirement
97 if(sensitiveCreate->data.t.size < (digestSize / 2))
98 return TPM_RC_SIZE;
99 #endif
100 }
101 // If this is a data blob, then anything that will get past the unmarshaling
102 // is OK
103 MemoryCopy2B(&sensitive->sensitive.bits.b, &sensitiveCreate->data.b,
104 sizeof(sensitive->sensitive.bits.t.buffer));
105 }
106 else
107 {
108 // The TPM is going to generate the data so set the size to be the
109 // size of the digest of the algorithm
110 sensitive->sensitive.bits.t.size =
111 DRBG_Generate(rand, sensitive->sensitive.bits.t.buffer, digestSize);
112 if(sensitive->sensitive.bits.t.size == 0)
113 return (g_inFailureMode) ? TPM_RC_FAILURE : TPM_RC_NO_RESULT;
114 }
115 return TPM_RC_SUCCESS;
116 }
10.2.6.3.4 CryptIsSchemeAnonymous()
This function is used to test a scheme to see if it is an anonymous scheme The only anonymous scheme
is ECDAA. ECDAA can be used to do things like U-Prove.
117 BOOL
118 CryptIsSchemeAnonymous(
119 TPM_ALG_ID scheme // IN: the scheme algorithm to test
120 )
121 {
122 return scheme == ALG_ECDAA_VALUE;
123 }
10.2.6.4.1 ParmDecryptSym()
124 void
125 ParmDecryptSym(
126 TPM_ALG_ID symAlg, // IN: the symmetric algorithm
127 TPM_ALG_ID hash, // IN: hash algorithm for KDFa
10.2.6.4.2 ParmEncryptSym()
158 void
159 ParmEncryptSym(
160 TPM_ALG_ID symAlg, // IN: symmetric algorithm
161 TPM_ALG_ID hash, // IN: hash algorithm for KDFa
162 UINT16 keySizeInBits, // IN: symmetric key size in bits
163 TPM2B *key, // IN: KDF HMAC key
164 TPM2B *nonceCaller, // IN: nonce caller
165 TPM2B *nonceTpm, // IN: nonce TPM
166 UINT32 dataSize, // IN: size of parameter buffer
167 BYTE *data // OUT: buffer to be encrypted
168 )
169 {
170 // KDF output buffer
171 // It contains parameters for the CFB encryption
172 BYTE symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
173
174 // Symmetric key size in bytes
175 UINT16 keySize = (keySizeInBits + 7) / 8;
176
177 TPM2B_IV iv;
178
179 iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits);
180 // See if there is any encryption to do
181 if(iv.t.size > 0)
182 {
183 // Generate key and iv
184 CryptKDFa(hash, key, CFB_KEY, nonceTpm, nonceCaller,
185 keySizeInBits + (iv.t.size * 8), symParmString, NULL, FALSE);
186 MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size);
187
188 CryptSymmetricEncrypt(data, symAlg, keySizeInBits, symParmString, &iv,
189 ALG_CFB_VALUE, dataSize, data);
190 }
191 return;
192 }
10.2.6.4.3 CryptGenerateKeySymmetric()
This function generates a symmetric cipher key. The derivation process is determined by the type of the
provided rand
10.2.6.4.4 CryptXORObfuscation()
This function implements XOR obfuscation. It should not be called if the hash algorithm is not
implemented. The only return value from this function is TPM_RC_SUCCESS.
237 void
238 CryptXORObfuscation(
239 TPM_ALG_ID hash, // IN: hash algorithm for KDF
240 TPM2B *key, // IN: KDF key
241 TPM2B *contextU, // IN: contextU
242 TPM2B *contextV, // IN: contextV
243 UINT32 dataSize, // IN: size of data buffer
244 BYTE *data // IN/OUT: data to be XORed in place
245 )
246 {
247 BYTE mask[MAX_DIGEST_SIZE]; // Allocate a digest sized buffer
248 BYTE *pm;
249 UINT32 i;
250 UINT32 counter = 0;
251 UINT16 hLen = CryptHashGetDigestSize(hash);
252 UINT32 requestSize = dataSize * 8;
253 INT32 remainBytes = (INT32)dataSize;
254
255 pAssert((key != NULL) && (data != NULL) && (hLen != 0));
256
257 // Call KDFa to generate XOR mask
258 for(; remainBytes > 0; remainBytes -= hLen)
259 {
260 // Make a call to KDFa to get next iteration
261 CryptKDFa(hash, key, XOR_KEY, contextU, contextV,
262 requestSize, mask, &counter, TRUE);
263
264 // XOR next piece of the data
265 pm = mask;
266 for(i = hLen < remainBytes ? hLen : remainBytes; i > 0; i--)
267 *data++ ^= *pm++;
268 }
269 return;
270 }
10.2.6.5.1 CryptInit()
NOTE: The hash algorithms do not have to be tested, they just need to be available. They have to be tested before the
TPM can accept HMAC authorization or return any result that relies on a hash algorithm.
271 BOOL
272 CryptInit(
273 void
274 )
275 {
276 BOOL ok;
277 // Initialize the vector of implemented algorithms
278 AlgorithmGetImplementedVector(&g_implementedAlgorithms);
279
280 // Indicate that all test are necessary
281 CryptInitializeToTest();
282
283 // Do any library initializations that are necessary. If any fails,
284 // the caller should go into failure mode;
285 ok = SupportLibInit();
286 ok = ok && CryptSymInit();
287 ok = ok && CryptRandInit();
288 ok = ok && CryptHashInit();
289 #if ALG_RSA
290 ok = ok && CryptRsaInit();
291 #endif // ALG_RSA
292 #if ALG_ECC
293 ok = ok && CryptEccInit();
294 #endif // ALG_ECC
295 return ok;
296 }
10.2.6.5.2 CryptStartup()
This function is called by TPM2_Startup() to initialize the functions in this cryptographic library and in the
provided CryptoLibrary(). This function and CryptUtilInit() are both provided so that the implementation
may move the initialization around to get the best interaction.
297 BOOL
298 CryptStartup(
299 STARTUP_TYPE type // IN: the startup type
300 )
301 {
302 BOOL OK;
303 NOT_REFERENCED(type);
304
305 OK = CryptSymStartup() && CryptRandStartup() && CryptHashStartup()
306 #if ALG_RSA
307 && CryptRsaStartup()
308 #endif // ALG_RSA
309 #if ALG_ECC
310 && CryptEccStartup()
311 #endif // ALG_ECC
312 ;
313 #if ALG_ECC
314 // Don't directly check for SU_RESET because that is the default
315 if(OK && (type != SU_RESTART) && (type != SU_RESUME))
316 {
317 // If the shutdown was orderly, then the values recovered from NV will
318 // be OK to use.
319 // Get a new random commit nonce
320 gr.commitNonce.t.size = sizeof(gr.commitNonce.t.buffer);
321 CryptRandomGenerate(gr.commitNonce.t.size, gr.commitNonce.t.buffer);
322 // Reset the counter and commit array
323 gr.commitCounter = 0;
324 MemorySet(gr.commitArray, 0, sizeof(gr.commitArray));
325 }
326 #endif // ALG_ECC
327 return OK;
328 }
10.2.6.6.1 Introduction
These functions are used generically when a function of a general type (e.g., symmetric encryption) is
required. The functions will modify the parameters as required to interface to the indicated algorithms.
10.2.6.6.2 CryptIsAsymAlgorithm()
329 BOOL
330 CryptIsAsymAlgorithm(
331 TPM_ALG_ID algID // IN: algorithm ID
332 )
333 {
334 switch(algID)
335 {
336 #if ALG_RSA
337 case ALG_RSA_VALUE:
338 #endif
339 #if ALG_ECC
340 case ALG_ECC_VALUE:
341 #endif
342 return TRUE;
343 break;
344 default:
345 break;
346 }
347 return FALSE;
348 }
10.2.6.6.3 CryptSecretEncrypt()
This function creates a secret value and its associated secret structure using an asymmetric algorithm.
This function is used by TPM2_Rewrap() TPM2_MakeCredential(), and TPM2_Duplicate().
349 TPM_RC
350 CryptSecretEncrypt(
351 OBJECT *encryptKey, // IN: encryption key object
352 const TPM2B *label, // IN: a null-terminated string as L
353 TPM2B_DATA *data, // OUT: secret value
354 TPM2B_ENCRYPTED_SECRET *secret // OUT: secret structure
355 )
356 {
357 TPMT_RSA_DECRYPT scheme;
358 TPM_RC result = TPM_RC_SUCCESS;
359 //
360 if(data == NULL || secret == NULL)
361 return TPM_RC_FAILURE;
362
363 // The output secret value has the size of the digest produced by the nameAlg.
364 data->t.size = CryptHashGetDigestSize(encryptKey->publicArea.nameAlg);
365 // The encryption scheme is OAEP using the nameAlg of the encrypt key.
366 scheme.scheme = ALG_OAEP_VALUE;
367 scheme.details.anySig.hashAlg = encryptKey->publicArea.nameAlg;
368
369 if(!IS_ATTRIBUTE(encryptKey->publicArea.objectAttributes, TPMA_OBJECT, decrypt))
370 return TPM_RC_ATTRIBUTES;
371 switch(encryptKey->publicArea.type)
372 {
373 #if ALG_RSA
374 case ALG_RSA_VALUE:
375 {
376 // Create secret data from RNG
377 CryptRandomGenerate(data->t.size, data->t.buffer);
378
379 // Encrypt the data by RSA OAEP into encrypted secret
380 result = CryptRsaEncrypt((TPM2B_PUBLIC_KEY_RSA *)secret, &data->b,
381 encryptKey, &scheme, label, NULL);
382 }
383 break;
384 #endif // ALG_RSA
385
386 #if ALG_ECC
387 case ALG_ECC_VALUE:
388 {
389 TPMS_ECC_POINT eccPublic;
390 TPM2B_ECC_PARAMETER eccPrivate;
391 TPMS_ECC_POINT eccSecret;
392 BYTE *buffer = secret->t.secret;
393
394 // Need to make sure that the public point of the key is on the
395 // curve defined by the key.
396 if(!CryptEccIsPointOnCurve(
397 encryptKey->publicArea.parameters.eccDetail.curveID,
398 &encryptKey->publicArea.unique.ecc))
399 result = TPM_RC_KEY;
400 else
401 {
402 // Call crypto engine to create an auxiliary ECC key
403 // We assume crypt engine initialization should always success.
404 // Otherwise, TPM should go to failure mode.
405
406 CryptEccNewKeyPair(&eccPublic, &eccPrivate,
407 encryptKey->publicArea.parameters.eccDetail.curveID);
408 // Marshal ECC public to secret structure. This will be used by the
409 // recipient to decrypt the secret with their private key.
410 secret->t.size = TPMS_ECC_POINT_Marshal(&eccPublic, &buffer, NULL);
411
412 // Compute ECDH shared secret which is R = [d]Q where d is the
413 // private part of the ephemeral key and Q is the public part of a
414 // TPM key. TPM_RC_KEY error return from CryptComputeECDHSecret
415 // because the auxiliary ECC key is just created according to the
416 // parameters of input ECC encrypt key.
417 if(CryptEccPointMultiply(&eccSecret,
418 encryptKey->publicArea.parameters.eccDetail.curveID,
419 &encryptKey->publicArea.unique.ecc, &eccPrivate,
420 NULL, NULL)
421 != TPM_RC_SUCCESS)
10.2.6.6.4 CryptSecretDecrypt()
Decrypt a secret value by asymmetric (or symmetric) algorithm This function is used for
ActivateCredential() and Import for asymmetric decryption, and StartAuthSession() for both asymmetric
and symmetric decryption process
453 TPM_RC
454 CryptSecretDecrypt(
455 OBJECT *decryptKey, // IN: decrypt key
456 TPM2B_NONCE *nonceCaller, // IN: nonceCaller. It is needed for
457 // symmetric decryption. For
458 // asymmetric decryption, this
10.2.6.6.5 CryptParameterEncryption()
629 void
630 CryptParameterEncryption(
631 TPM_HANDLE handle, // IN: encrypt session handle
632 TPM2B *nonceCaller, // IN: nonce caller
633 UINT16 leadingSizeInByte, // IN: the size of the leading size field in
634 // bytes
635 TPM2B_AUTH *extraKey, // IN: additional key material other than
636 // sessionAuth
637 BYTE *buffer // IN/OUT: parameter buffer to be encrypted
638 )
639 {
640 SESSION *session = SessionGet(handle); // encrypt session
641 TPM2B_TYPE(TEMP_KEY, (sizeof(extraKey->t.buffer)
642 + sizeof(session->sessionKey.t.buffer)));
643 TPM2B_TEMP_KEY key; // encryption key
644 UINT32 cipherSize = 0; // size of cipher text
645 //
646 // Retrieve encrypted data size.
647 if(leadingSizeInByte == 2)
648 {
649 // Extract the first two bytes as the size field as the data size
650 // encrypt
651 cipherSize = (UINT32)BYTE_ARRAY_TO_UINT16(buffer);
652 // advance the buffer
653 buffer = &buffer[2];
654 }
655 #ifdef TPM4B
656 else if(leadingSizeInByte == 4)
657 {
658 // use the first four bytes to indicate the number of bytes to encrypt
659 cipherSize = BYTE_ARRAY_TO_UINT32(buffer);
660 //advance pointer
661 buffer = &buffer[4];
662 }
663 #endif
664 else
665 {
666 FAIL(FATAL_ERROR_INTERNAL);
667 }
668
669 // Compute encryption key by concatenating sessionKey with extra key
670 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
671 MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer));
672
673 if(session->symmetric.algorithm == ALG_XOR_VALUE)
674
675 // XOR parameter encryption formulation:
676 // XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder)
677 CryptXORObfuscation(session->authHashAlg, &(key.b),
678 &(session->nonceTPM.b),
679 nonceCaller, cipherSize, buffer);
680 else
681 ParmEncryptSym(session->symmetric.algorithm, session->authHashAlg,
682 session->symmetric.keyBits.aes, &(key.b),
683 nonceCaller, &(session->nonceTPM.b),
684 cipherSize, buffer);
685 return;
686 }
10.2.6.6.6 CryptParameterDecryption()
687 TPM_RC
688 CryptParameterDecryption(
689 TPM_HANDLE handle, // IN: encrypted session handle
690 TPM2B *nonceCaller, // IN: nonce caller
691 UINT32 bufferSize, // IN: size of parameter buffer
692 UINT16 leadingSizeInByte, // IN: the size of the leading size field in
693 // byte
694 TPM2B_AUTH *extraKey, // IN: the authValue
695 BYTE *buffer // IN/OUT: parameter buffer to be decrypted
696 )
697 {
698 SESSION *session = SessionGet(handle); // encrypt session
699 // The HMAC key is going to be the concatenation of the session key and any
700 // additional key material (like the authValue). The size of both of these
701 // is the size of the buffer which can contain a TPMT_HA.
702 TPM2B_TYPE(HMAC_KEY, (sizeof(extraKey->t.buffer)
703 + sizeof(session->sessionKey.t.buffer)));
10.2.6.6.7 CryptComputeSymmetricUnique()
This function computes the unique field in public area for symmetric objects.
749 void
750 CryptComputeSymmetricUnique(
751 TPMT_PUBLIC *publicArea, // IN: the object's public area
752 TPMT_SENSITIVE *sensitive, // IN: the associated sensitive area
753 TPM2B_DIGEST *unique // OUT: unique buffer
754 )
755 {
756 // For parents (symmetric and derivation), use an HMAC to compute
757 // the 'unique' field
758 if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
759 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt))
760 {
761 // Unique field is HMAC(sensitive->seedValue, sensitive->sensitive)
762 HMAC_STATE hmacState;
10.2.6.6.8 CryptCreateObject()
This function creates an object. For an asymmetric key, it will create a key pair and, for a parent key, a
seed value for child protections.
For an symmetric object, (TPM_ALG_SYMCIPHER or TPM_ALG_KEYEDHASH), it will create a secret
key if the caller did not provide one. It will create a random secret seed value that is hashed with the
secret value to create the public unique value.
publicArea, sensitive, and sensitiveCreate are the only required parameters and are the only ones that
are used by TPM2_Create(). The other parameters are optional and are used when the generated Object
needs to be deterministic. This is the case for both Primary Objects and Derived Objects.
When a seed value is provided, a RAND_STATE will be populated and used for all operations in the
object generation that require a random number. In the simplest case, TPM2_CreatePrimary() will use
seed, label and context with context being the hash of the template. If the Primary Object is in the
Endorsement hierarchy, it will also populate proof with ehProof.
For derived keys, seed will be the secret value from the parent, label and context will be set according to
the parameters of TPM2_CreateLoaded() and hashAlg will be set which causes the RAND_STATE to be
a KDF generator.
780 TPM_RC
781 CryptCreateObject(
782 OBJECT *object, // IN: new object structure pointer
783 TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation
784 RAND_STATE *rand // IN: the random number generator
785 // to use
786 )
787 {
788 TPMT_PUBLIC *publicArea = &object->publicArea;
789 TPMT_SENSITIVE *sensitive = &object->sensitive;
790 TPM_RC result = TPM_RC_SUCCESS;
791 //
792 // Set the sensitive type for the object
793 sensitive->sensitiveType = publicArea->type;
794
795 // For all objects, copy the initial authorization data
796 sensitive->authValue = sensitiveCreate->userAuth;
797
798 // If the TPM is the source of the data, set the size of the provided data to
799 // zero so that there's no confusion about what to do.
800 if(IS_ATTRIBUTE(publicArea->objectAttributes,
801 TPMA_OBJECT, sensitiveDataOrigin))
802 sensitiveCreate->data.t.size = 0;
803
804 // Generate the key and unique fields for the asymmetric keys and just the
805 // sensitive value for symmetric object
806 switch(publicArea->type)
807 {
808 #if ALG_RSA
809 // Create RSA key
810 case ALG_RSA_VALUE:
811 // RSA uses full object so that it has a place to put the private
812 // exponent
813 result = CryptRsaGenerateKey(publicArea, sensitive, rand);
814 break;
815 #endif // ALG_RSA
816
817 #if ALG_ECC
818 // Create ECC key
819 case ALG_ECC_VALUE:
820 result = CryptEccGenerateKey(publicArea, sensitive, rand);
821 break;
822 #endif // ALG_ECC
823 case ALG_SYMCIPHER_VALUE:
824 result = CryptGenerateKeySymmetric(publicArea, sensitive,
825 sensitiveCreate, rand);
826 break;
827 case ALG_KEYEDHASH_VALUE:
828 result = CryptGenerateKeyedHash(publicArea, sensitive,
829 sensitiveCreate, rand);
830 break;
831 default:
832 FAIL(FATAL_ERROR_INTERNAL);
833 break;
834 }
835 if(result != TPM_RC_SUCCESS)
836 return result;
837 // Create the sensitive seed value
838 // If this is a primary key in the endorsement hierarchy, stir the DRBG state
839 // This implementation uses both shProof and ehProof to make sure that there
840 // is no leakage of either.
841 if(object->attributes.primary && object->attributes.epsHierarchy)
842 {
843 DRBG_AdditionalData((DRBG_STATE *)rand, &gp.shProof.b);
844 DRBG_AdditionalData((DRBG_STATE *)rand, &gp.ehProof.b);
845 }
846 // Generate a seedValue that is the size of the digest produced by nameAlg
847 sensitive->seedValue.t.size =
848 DRBG_Generate(rand, sensitive->seedValue.t.buffer,
849 CryptHashGetDigestSize(publicArea->nameAlg));
850 if(g_inFailureMode)
851 return TPM_RC_FAILURE;
852 else if(sensitive->seedValue.t.size == 0)
10.2.6.6.9 CryptGetSignHashAlg()
Get the hash algorithm of signature from a TPMT_SIGNATURE structure. It assumes the signature is not
NULL This is a function for easy access
872 TPMI_ALG_HASH
873 CryptGetSignHashAlg(
874 TPMT_SIGNATURE *auth // IN: signature
875 )
876 {
877 if(auth->sigAlg == ALG_NULL_VALUE)
878 FAIL(FATAL_ERROR_INTERNAL);
879
880 // Get authHash algorithm based on signing scheme
881 switch(auth->sigAlg)
882 {
883 #if ALG_RSA
884 // If RSA is supported, both RSASSA and RSAPSS are required
885 # if !defined ALG_RSASSA_VALUE || !defined ALG_RSAPSS_VALUE
886 # error "RSASSA and RSAPSS are required for RSA"
887 # endif
888 case ALG_RSASSA_VALUE:
889 return auth->signature.rsassa.hash;
890 case ALG_RSAPSS_VALUE:
891 return auth->signature.rsapss.hash;
892 #endif // ALG_RSA
893
894 #if ALG_ECC
895 // If ECC is defined, ECDSA is mandatory
896 # if !ALG_ECDSA
897 # error "ECDSA is requried for ECC"
898 # endif
899 case ALG_ECDSA_VALUE:
900 // SM2 and ECSCHNORR are optional
901
902 # if ALG_SM2
903 case ALG_SM2_VALUE:
904 # endif
905 # if ALG_ECSCHNORR
906 case ALG_ECSCHNORR_VALUE:
907 # endif
908 //all ECC signatures look the same
909 return auth->signature.ecdsa.hash;
910
911 # if ALG_ECDAA
912 // Don't know how to verify an ECDAA signature
913 case ALG_ECDAA_VALUE:
914 break;
915 # endif
916
917 #endif // ALG_ECC
918
919 case ALG_HMAC_VALUE:
920 return auth->signature.hmac.hashAlg;
921
922 default:
923 break;
924 }
925 return ALG_NULL_VALUE;
926 }
10.2.6.6.10 CryptIsSplitSign()
This function us used to determine if the signing operation is a split signing operation that required a
TPM2_Commit().
927 BOOL
928 CryptIsSplitSign(
929 TPM_ALG_ID scheme // IN: the algorithm selector
930 )
931 {
932 switch(scheme)
933 {
934 # if ALG_ECDAA
935 case ALG_ECDAA_VALUE:
936 return TRUE;
937 break;
938 # endif // ALG_ECDAA
939 default:
940 return FALSE;
941 break;
942 }
943 }
10.2.6.6.11 CryptIsAsymSignScheme()
944 BOOL
945 CryptIsAsymSignScheme(
946 TPMI_ALG_PUBLIC publicType, // IN: Type of the object
947 TPMI_ALG_ASYM_SCHEME scheme // IN: the scheme
948 )
949 {
950 BOOL isSignScheme = TRUE;
951
952 switch(publicType)
953 {
954 #if ALG_RSA
955 case ALG_RSA_VALUE:
956 switch(scheme)
957 {
958 # if !ALG_RSASSA || !ALG_RSAPSS
959 # error "RSASSA and PSAPSS required if RSA used."
960 # endif
961 case ALG_RSASSA_VALUE:
962 case ALG_RSAPSS_VALUE:
963 break;
964 default:
965 isSignScheme = FALSE;
966 break;
967 }
968 break;
969 #endif // ALG_RSA
970
971 #if ALG_ECC
972 // If ECC is implemented ECDSA is required
973 case ALG_ECC_VALUE:
974 switch(scheme)
975 {
976 // Support for ECDSA is required for ECC
977 case ALG_ECDSA_VALUE:
978 #if ALG_ECDAA // ECDAA is optional
979 case ALG_ECDAA_VALUE:
980 #endif
981 #if ALG_ECSCHNORR // Schnorr is also optional
982 case ALG_ECSCHNORR_VALUE:
983 #endif
984 #if ALG_SM2 // SM2 is optional
985 case ALG_SM2_VALUE:
986 #endif
987 break;
988 default:
989 isSignScheme = FALSE;
990 break;
991 }
992 break;
993 #endif // ALG_ECC
994 default:
995 isSignScheme = FALSE;
996 break;
997 }
998 return isSignScheme;
999 }
10.2.6.6.12 CryptIsAsymDecryptScheme()
1000 BOOL
1001 CryptIsAsymDecryptScheme(
1002 TPMI_ALG_PUBLIC publicType, // IN: Type of the object
1003 TPMI_ALG_ASYM_SCHEME scheme // IN: the scheme
1004 )
1005 {
1006 BOOL isDecryptScheme = TRUE;
1007
1008 switch(publicType)
1009 {
1010 #if ALG_RSA
1011 case ALG_RSA_VALUE:
1012 switch(scheme)
1013 {
1014 case ALG_RSAES_VALUE:
1015 case ALG_OAEP_VALUE:
1016 break;
1017 default:
1018 isDecryptScheme = FALSE;
1019 break;
1020 }
1021 break;
10.2.6.6.13 CryptSelectSignScheme()
This function is used by the attestation and signing commands. It implements the rules for selecting the
signature scheme to use in signing. This function requires that the signing key either be TPM_RH_NULL
or be loaded.
If a default scheme is defined in object, the default scheme should be chosen, otherwise, the input
scheme should be chosen. In the case that both object and input scheme has a non-NULL scheme
algorithm, if the schemes are compatible, the input scheme will be chosen.
This function should not be called if 'signObject->publicArea.type' == ALG_SYMCIPHER.
1052 BOOL
1053 CryptSelectSignScheme(
1054 OBJECT *signObject, // IN: signing key
1055 TPMT_SIG_SCHEME *scheme // IN/OUT: signing scheme
1056 )
1057 {
1058 TPMT_SIG_SCHEME *objectScheme;
1059 TPMT_PUBLIC *publicArea;
1060 BOOL OK;
1061
1062 // If the signHandle is TPM_RH_NULL, then the NULL scheme is used, regardless
1063 // of the setting of scheme
1064 if(signObject == NULL)
1065 {
1066 OK = TRUE;
1067 scheme->scheme = ALG_NULL_VALUE;
1068 scheme->details.any.hashAlg = ALG_NULL_VALUE;
1069 }
1070 else
1071 {
1072 // assignment to save typing.
1073 publicArea = &signObject->publicArea;
1074
1075 // A symmetric cipher can be used to encrypt and decrypt but it can't
1076 // be used for signing
1077 if(publicArea->type == ALG_SYMCIPHER_VALUE)
1078 return FALSE;
1079 // Point to the scheme object
1080 if(CryptIsAsymAlgorithm(publicArea->type))
1081 objectScheme =
1082 (TPMT_SIG_SCHEME *)&publicArea->parameters.asymDetail.scheme;
1083 else
1084 objectScheme =
1085 (TPMT_SIG_SCHEME *)&publicArea->parameters.keyedHashDetail.scheme;
1086
1087 // If the object doesn't have a default scheme, then use the
1088 // input scheme.
1089 if(objectScheme->scheme == ALG_NULL_VALUE)
1090 {
1091 // Input and default can't both be NULL
1092 OK = (scheme->scheme != ALG_NULL_VALUE);
1093 // Assume that the scheme is compatible with the key. If not,
1094 // an error will be generated in the signing operation.
1095 }
1096 else if(scheme->scheme == ALG_NULL_VALUE)
1097 {
1098 // input scheme is NULL so use default
1099
1100 // First, check to see if the default requires that the caller
1101 // provided scheme data
1102 OK = !CryptIsSplitSign(objectScheme->scheme);
1103 if(OK)
1104 {
1105 // The object has a scheme and the input is TPM_ALG_NULL so copy
1106 // the object scheme as the final scheme. It is better to use a
1107 // structure copy than a copy of the individual fields.
1108 *scheme = *objectScheme;
1109 }
1110 }
1111 else
1112 {
1113 // Both input and object have scheme selectors
1114 // If the scheme and the hash are not the same then...
1115 // NOTE: the reason that there is no copy here is that the input
1116 // might contain extra data for a split signing scheme and that
1117 // data is not in the object so, it has to be preserved.
1118 OK = (objectScheme->scheme == scheme->scheme)
1119 && (objectScheme->details.any.hashAlg
1120 == scheme->details.any.hashAlg);
1121 }
1122 }
1123 return OK;
1124 }
10.2.6.6.14 CryptSign()
Sign a digest with asymmetric key or HMAC. This function is called by attestation commands and the
generic TPM2_Sign() command. This function checks the key scheme and digest size. It does not check
if the sign operation is allowed for restricted key. It should be checked before the function is called. The
function will assert if the key is not a signing key.
1125 TPM_RC
1126 CryptSign(
1127 OBJECT *signKey, // IN: signing key
1128 TPMT_SIG_SCHEME *signScheme, // IN: sign scheme.
1129 TPM2B_DIGEST *digest, // IN: The digest being signed
1130 TPMT_SIGNATURE *signature // OUT: signature
1131 )
1132 {
1133 TPM_RC result = TPM_RC_SCHEME;
1134
1135 // Initialize signature scheme
1136 signature->sigAlg = signScheme->scheme;
1137
1138 // If the signature algorithm is TPM_ALG_NULL or the signing key is NULL,
1139 // then we are done
1140 if((signature->sigAlg == ALG_NULL_VALUE) || (signKey == NULL))
1141 return TPM_RC_SUCCESS;
1142
1143 // Initialize signature hash
1144 // Note: need to do the check for TPM_ALG_NULL first because the null scheme
1145 // doesn't have a hashAlg member.
1146 signature->signature.any.hashAlg = signScheme->details.any.hashAlg;
1147
1148 // perform sign operation based on different key type
1149 switch(signKey->publicArea.type)
1150 {
1151 #if ALG_RSA
1152 case ALG_RSA_VALUE:
1153 result = CryptRsaSign(signature, signKey, digest, NULL);
1154 break;
1155 #endif // ALG_RSA
1156 #if ALG_ECC
1157 case ALG_ECC_VALUE:
1158 // The reason that signScheme is passed to CryptEccSign but not to the
1159 // other signing methods is that the signing for ECC may be split and
1160 // need the 'r' value that is in the scheme but not in the signature.
1161 result = CryptEccSign(signature, signKey, digest,
1162 (TPMT_ECC_SCHEME *)signScheme, NULL);
1163 break;
1164 #endif // ALG_ECC
1165 case ALG_KEYEDHASH_VALUE:
1166 result = CryptHmacSign(signature, signKey, digest);
1167 break;
1168 default:
1169 FAIL(FATAL_ERROR_INTERNAL);
1170 break;
1171 }
1172 return result;
1173 }
10.2.6.6.15 CryptValidateSignature()
1174 TPM_RC
1175 CryptValidateSignature(
1176 TPMI_DH_OBJECT keyHandle, // IN: The handle of sign key
1177 TPM2B_DIGEST *digest, // IN: The digest being validated
1178 TPMT_SIGNATURE *signature // IN: signature
1179 )
1180 {
1181 // NOTE: HandleToObject will either return a pointer to a loaded object or
1182 // will assert. It will never return a non-valid value. This makes it save
1183 // to initialize 'publicArea' with the return value from HandleToObject()
1184 // without checking it first.
1185 OBJECT *signObject = HandleToObject(keyHandle);
1186 TPMT_PUBLIC *publicArea = &signObject->publicArea;
1187 TPM_RC result = TPM_RC_SCHEME;
1188
1189 // The input unmarshaling should prevent any input signature from being
1190 // a NULL signature, but just in case
1191 if(signature->sigAlg == ALG_NULL_VALUE)
1192 return TPM_RC_SIGNATURE;
1193
1194 switch(publicArea->type)
1195 {
1196 #if ALG_RSA
1197 case ALG_RSA_VALUE:
1198 {
1199 //
1200 // Call RSA code to verify signature
1201 result = CryptRsaValidateSignature(signature, signObject, digest);
1202 break;
1203 }
1204 #endif // ALG_RSA
1205
1206 #if ALG_ECC
1207 case ALG_ECC_VALUE:
1208 result = CryptEccValidateSignature(signature, signObject, digest);
1209 break;
1210 #endif // ALG_ECC
1211
1212 case ALG_KEYEDHASH_VALUE:
1213 if(signObject->attributes.publicOnly)
1214 result = TPM_RCS_HANDLE;
1215 else
1216 result = CryptHMACVerifySignature(signObject, digest, signature);
1217 break;
1218 default:
1219 break;
1220 }
10.2.6.6.16 CryptGetTestResult
NOTE: the behavior in this function is NOT the correct behavior for a real TPM implementation. An artificial behavior is
placed here due to the limitation of a software simulation environment. For the correct behavior, consult the part
3 specification for TPM2_GetTestResult().
1223 TPM_RC
1224 CryptGetTestResult(
1225 TPM2B_MAX_BUFFER *outData // OUT: test result data
1226 )
1227 {
1228 outData->t.size = 0;
1229 return TPM_RC_SUCCESS;
1230 }
10.2.6.6.17 CryptValidateKeys()
This function is used to verify that the key material of and object is valid. For a publicOnly object, the key
is verified for size and, if it is an ECC key, it is verified to be on the specified curve. For a key with a
sensitive area, the binding between the public and private parts of the key are verified. If the nameAlg of
the key is TPM_ALG_NULL, then the size of the sensitive area is verified but the public portion is not
verified, unless the key is an RSA key. For an RSA key, the reason for loading the sensitive area is to use
it. The only way to use a private RSA key is to compute the private exponent. To compute the private
exponent, the public modulus is used.
1231 TPM_RC
1232 CryptValidateKeys(
1233 TPMT_PUBLIC *publicArea,
1234 TPMT_SENSITIVE *sensitive,
1235 TPM_RC blamePublic,
1236 TPM_RC blameSensitive
1237 )
1238 {
1239 TPM_RC result;
1240 UINT16 keySizeInBytes;
1241 UINT16 digestSize = CryptHashGetDigestSize(publicArea->nameAlg);
1242 TPMU_PUBLIC_PARMS *params = &publicArea->parameters;
1243 TPMU_PUBLIC_ID *unique = &publicArea->unique;
1244
1245 if(sensitive != NULL)
1246 {
1247 // Make sure that the types of the public and sensitive are compatible
1248 if(publicArea->type != sensitive->sensitiveType)
1249 return TPM_RCS_TYPE + blameSensitive;
1250 // Make sure that the authValue is not bigger than allowed
1251 // If there is no name algorithm, then the size just needs to be less than
1252 // the maximum size of the buffer used for authorization. That size check
1253 // was made during unmarshaling of the sensitive area
1254 if((sensitive->authValue.t.size) > digestSize && (digestSize > 0))
1255 return TPM_RCS_SIZE + blameSensitive;
1256 }
1257 switch(publicArea->type)
1258 {
1259 #if ALG_RSA
1260 case ALG_RSA_VALUE:
1261 keySizeInBytes = BITS_TO_BYTES(params->rsaDetail.keyBits);
1262
1263 // Regardless of whether there is a sensitive area, the public modulus
1264 // needs to have the correct size. Otherwise, it can't be used for
1265 // any public key operation nor can it be used to compute the private
1266 // exponent.
1267 // NOTE: This implementation only supports key sizes that are multiples
1268 // of 1024 bits which means that the MSb of the 0th byte will always be
1269 // SET in any prime and in the public modulus.
1270 if((unique->rsa.t.size != keySizeInBytes)
1271 || (unique->rsa.t.buffer[0] < 0x80))
1272 return TPM_RCS_KEY + blamePublic;
1273 if(params->rsaDetail.exponent != 0
1274 && params->rsaDetail.exponent < 7)
1275 return TPM_RCS_VALUE + blamePublic;
1276 if(sensitive != NULL)
1277 {
1278 // If there is a sensitive area, it has to be the correct size
1279 // including having the correct high order bit SET.
1280 if(((sensitive->sensitive.rsa.t.size * 2) != keySizeInBytes)
1281 || (sensitive->sensitive.rsa.t.buffer[0] < 0x80))
1282 return TPM_RCS_KEY_SIZE + blameSensitive;
1283 }
1284 break;
1285 #endif
1286 #if ALG_ECC
1287 case ALG_ECC_VALUE:
1288 {
1289 TPMI_ECC_CURVE curveId;
1290 curveId = params->eccDetail.curveID;
1291 keySizeInBytes = BITS_TO_BYTES(CryptEccGetKeySizeForCurve(curveId));
1292 if(sensitive == NULL)
1293 {
1294 // Validate the public key size
1295 if(unique->ecc.x.t.size != keySizeInBytes
1296 || unique->ecc.y.t.size != keySizeInBytes)
1297 return TPM_RCS_KEY + blamePublic;
1298 if(publicArea->nameAlg != ALG_NULL_VALUE)
1299 {
1300 if(!CryptEccIsPointOnCurve(curveId, &unique->ecc))
1301 return TPM_RCS_ECC_POINT + blamePublic;
1302 }
1303 }
1304 else
1305 {
1306 // If the nameAlg is TPM_ALG_NULL, then only verify that the
1307 // private part of the key is OK.
1308 if(!CryptEccIsValidPrivateKey(&sensitive->sensitive.ecc,
1309 curveId))
1310 return TPM_RCS_KEY_SIZE;
1311 if(publicArea->nameAlg != ALG_NULL_VALUE)
1312 {
1313 // Full key load, verify that the public point belongs to the
1314 // private key.
1315 TPMS_ECC_POINT toCompare;
1316 result = CryptEccPointMultiply(&toCompare, curveId, NULL,
1317 &sensitive->sensitive.ecc,
1384 }
1385 else
1386 return TPM_RCS_SCHEME + blamePublic;
1387 if(sensitive->sensitive.bits.t.size > maxSize)
1388 return TPM_RCS_KEY_SIZE + blameSensitive;
1389 }
1390 // If there is a nameAlg, check the binding
1391 if(publicArea->nameAlg != ALG_NULL_VALUE)
1392 {
1393 TPM2B_DIGEST compare;
1394 if(sensitive->seedValue.t.size != digestSize)
1395 return TPM_RCS_KEY_SIZE + blameSensitive;
1396
1397 CryptComputeSymmetricUnique(publicArea, sensitive, &compare);
1398 if(!MemoryEqual2B(&unique->sym.b, &compare.b))
1399 return TPM_RC_BINDING;
1400 }
1401 }
1402 break;
1403 }
1404 // For a parent, need to check that the seedValue is the correct size for
1405 // protections. It should be at least half the size of the nameAlg
1406 if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
1407 && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
1408 && sensitive != NULL
1409 && publicArea->nameAlg != ALG_NULL_VALUE)
1410 {
1411 if((sensitive->seedValue.t.size < (digestSize / 2))
1412 || (sensitive->seedValue.t.size > digestSize))
1413 return TPM_RCS_SIZE + blameSensitive;
1414 }
1415 return TPM_RC_SUCCESS;
1416 }
10.2.6.6.18 CryptSelectMac()
This function is used to set the MAC scheme based on the key parameters and the input scheme.
1417 TPM_RC
1418 CryptSelectMac(
1419 TPMT_PUBLIC *publicArea,
1420 TPMI_ALG_MAC_SCHEME *inMac
1421 )
1422 {
1423 TPM_ALG_ID macAlg = ALG_NULL_VALUE;
1424 switch(publicArea->type)
1425 {
1426 case ALG_KEYEDHASH_VALUE:
1427 {
1428 // Local value to keep lines from getting too long
1429 TPMT_KEYEDHASH_SCHEME *scheme;
1430 scheme = &publicArea->parameters.keyedHashDetail.scheme;
1431 // Expect that the scheme is either HMAC or NULL
1432 if(scheme->scheme != ALG_NULL_VALUE)
1433 macAlg = scheme->details.hmac.hashAlg;
1434 break;
1435 }
10.2.6.6.19 CryptMacIsValidForKey()
Check to see if the key type is compatible with the mac type
1468 BOOL
1469 CryptMacIsValidForKey(
1470 TPM_ALG_ID keyType,
1471 TPM_ALG_ID macAlg,
1472 BOOL flag
1473 )
1474 {
1475 switch(keyType)
1476 {
1477 case ALG_KEYEDHASH_VALUE:
1478 return CryptHashIsValidAlg(macAlg, flag);
1479 break;
1480 case ALG_SYMCIPHER_VALUE:
1481 return CryptSmacIsValidAlg(macAlg, flag);
1482 break;
1483 default:
1484 break;
1485 }
1486 return FALSE;
1487 }
10.2.6.6.20 CryptSmacIsValidAlg()
This function is used to test if an algorithm is a supported SMAC algorithm. It needs to be updated as new
algorithms are added.
1488 BOOL
1489 CryptSmacIsValidAlg(
1490 TPM_ALG_ID alg,
1491 BOOL FLAG // IN: Indicates if TPM_ALG_NULL is valid
1492 )
1493 {
1494 switch (alg)
1495 {
1496 #if ALG_CMAC
1497 case ALG_CMAC_VALUE:
1498 return TRUE;
1499 break;
1500 #endif
1501 case ALG_NULL_VALUE:
1502 return FLAG;
1503 break;
1504 default:
1505 return FALSE;
1506 }
1507 }
10.2.6.6.21 CryptSymModeIsValid()
Function checks to see if an algorithm ID is a valid, symmetric block cipher mode for the TPM. If flag is
SET, them TPM_ALG_NULL is a valid mode. not include the modes used for SMAC
1508 BOOL
1509 CryptSymModeIsValid(
1510 TPM_ALG_ID mode,
1511 BOOL flag
1512 )
1513 {
1514 switch(mode)
1515 {
1516 #if ALG_CTR
1517 case ALG_CTR_VALUE:
1518 #endif // ALG_CTR
1519 #if ALG_OFB
1520 case ALG_OFB_VALUE:
1521 #endif // ALG_OFB
1522 #if ALG_CBC
1523 case ALG_CBC_VALUE:
1524 #endif // ALG_CBC
1525 #if ALG_CFB
1526 case ALG_CFB_VALUE:
1527 #endif // ALG_CFB
1528 #if ALG_ECB
1529 case ALG_ECB_VALUE:
1530 #endif // ALG_ECB
1531 return TRUE;
1532 case ALG_NULL_VALUE:
1533 return flag;
1534 break;
1535 default:
1536 break;
1537 }
1538 return FALSE;
1539 }
10.2.7 CryptSelfTest.c
10.2.7.1 Introduction
The functions in this file are designed to support self-test of cryptographic functions in the TPM. The TPM
allows the user to decide whether to run self-test on a demand basis or to run all the self-tests before
proceeding.
The self-tests are controlled by a set of bit vectors. The g_untestedDecryptionAlgorithms vector has a bit
for each decryption algorithm that needs to be tested and g_untestedEncryptionAlgorithms has a bit for
each encryption algorithm that needs to be tested. Before an algorithm is used, the appropriate vector is
checked (indexed using the algorithm ID). If the bit is 1, then the test function should be called.
For more information, see TpmSelfTests().txt
1 #include "Tpm.h"
10.2.7.2 Functions
10.2.7.2.1 RunSelfTest()
2 static TPM_RC
3 CryptRunSelfTests(
4 ALGORITHM_VECTOR *toTest // IN: the vector of the algorithms to test
5 )
6 {
7 TPM_ALG_ID alg;
8
9 // For each of the algorithms that are in the toTestVecor, need to run a
10 // test
11 for(alg = TPM_ALG_FIRST; alg <= TPM_ALG_LAST; alg++)
12 {
13 if(TEST_BIT(alg, *toTest))
14 {
15 TPM_RC result = CryptTestAlgorithm(alg, toTest);
16 if(result != TPM_RC_SUCCESS)
17 return result;
18 }
19 }
20 return TPM_RC_SUCCESS;
21 }
10.2.7.2.2 CryptSelfTest()
This function is called to start/complete a full self-test. If fullTest is NO, then only the untested algorithms
will be run. If fullTest is YES, then g_untestedDecryptionAlgorithms is reinitialized and then all tests are
run. This implementation of the reference design does not support processing outside the framework of a
TPM command. As a consequence, this command does not complete until all tests are done. Since this
can take a long time, the TPM will check after each test to see if the command is canceled. If so, then the
TPM will returned TPM_RC_CANCELLED. To continue with the self-tests, call TPM2_SelfTest(fullTest ==
No) and the TPM will complete the testing.
22 LIB_EXPORT
23 TPM_RC
24 CryptSelfTest(
25 TPMI_YES_NO fullTest // IN: if full test is required
26 )
27 {
28 #if SIMULATION
29 if(g_forceFailureMode)
30 FAIL(FATAL_ERROR_FORCED);
31 #endif
32
33 // If the caller requested a full test, then reset the to test vector so that
34 // all the tests will be run
35 if(fullTest == YES)
36 {
37 MemoryCopy(g_toTest,
38 g_implementedAlgorithms,
39 sizeof(g_toTest));
40 }
41 return CryptRunSelfTests(&g_toTest);
42 }
10.2.7.2.3 CryptIncrementalSelfTest()
This function is used to perform an incremental self-test. This implementation will perform the toTest
values before returning. That is, it assumes that the TPM cannot perform background tasks between
commands.
This command may be canceled. If it is, then there is no return result. However, this command can be run
again and the incremental progress will not be lost.
43 TPM_RC
44 CryptIncrementalSelfTest(
45 TPML_ALG *toTest, // IN: list of algorithms to be tested
46 TPML_ALG *toDoList // OUT: list of algorithms needing test
47 )
48 {
49 ALGORITHM_VECTOR toTestVector = {0};
50 TPM_ALG_ID alg;
51 UINT32 i;
52
53 pAssert(toTest != NULL && toDoList != NULL);
54 if(toTest->count > 0)
55 {
56 // Transcribe the toTest list into the toTestVector
57 for(i = 0; i < toTest->count; i++)
58 {
59 alg = toTest->algorithms[i];
60
61 // make sure that the algorithm value is not out of range
62 if((alg > TPM_ALG_LAST) || !TEST_BIT(alg, g_implementedAlgorithms))
63 return TPM_RC_VALUE;
64 SET_BIT(alg, toTestVector);
65 }
66 // Run the test
67 if(CryptRunSelfTests(&toTestVector) == TPM_RC_CANCELED)
68 return TPM_RC_CANCELED;
69 }
70 // Fill in the toDoList with the algorithms that are still untested
71 toDoList->count = 0;
72
73 for(alg = TPM_ALG_FIRST;
74 toDoList->count < MAX_ALG_LIST_SIZE && alg <= TPM_ALG_LAST;
75 alg++)
76 {
77 if(TEST_BIT(alg, g_toTest))
78 toDoList->algorithms[toDoList->count++] = alg;
79 }
80 return TPM_RC_SUCCESS;
81 }
10.2.7.2.4 CryptInitializeToTest()
This function will initialize the data structures for testing all the algorithms.
82 void
83 CryptInitializeToTest(
84 void
85 )
86 {
87 // Indicate that nothing has been tested
88 memset(&g_cryptoSelfTestState, 0, sizeof(g_cryptoSelfTestState));
89
90 // Copy the implemented algorithm vector
91 MemoryCopy(g_toTest, g_implementedAlgorithms, sizeof(g_toTest));
92
93 // Setting the algorithm to null causes the test function to just clear
94 // out any algorithms for which there is no test.
95 CryptTestAlgorithm(TPM_ALG_ERROR, &g_toTest);
96
97 return;
98 }
10.2.7.2.5 CryptTestAlgorithm()
Only point of contact with the actual self tests. If a self-test fails, there is no return and the TPM goes into
failure mode. The call to TestAlgorithm() uses an algorithm selector and a bit vector. When the test is run,
the corresponding bit in toTest and in g_toTest is CLEAR. If toTest is NULL, then only the bit in g_toTest
is CLEAR. There is a special case for the call to TestAlgorithm(). When alg is ALG_ERROR,
TestAlgorithm() will CLEAR any bit in toTest for which it has no test. This allows the knowledge about
which algorithms have test to be accessed through the interface that provides the test.
99 LIB_EXPORT
100 TPM_RC
101 CryptTestAlgorithm(
102 TPM_ALG_ID alg,
103 ALGORITHM_VECTOR *toTest
104 )
105 {
10.2.8 CryptEccData.c
1 #include "Tpm.h"
2 #include "OIDs.h"
This file contains the ECC curve data. The format of the data depends on the setting of
USE_BN_ECC_DATA. If it is defined, then the TPM's BigNum() format is used. Otherwise, it is kept in
TPM2B format. The purpose of having the data in BigNum() format is so that it does not have to be
reformatted before being used by the crypto library.
3 #if ALG_ECC
4 #if USE_BN_ECC_DATA
5 # define TO_ECC_64 TO_CRYPT_WORD_64
6 # define TO_ECC_56(a, b, c, d, e, f, g) TO_ECC_64(0, a, b, c, d, e, f, g)
7 # define TO_ECC_48(a, b, c, d, e, f) TO_ECC_64(0, 0, a, b, c, d, e, f)
8 # define TO_ECC_40(a, b, c, d, e) TO_ECC_64(0, 0, 0, a, b, c, d, e)
9 # if RADIX_BITS > 32
10 # define TO_ECC_32(a, b, c, d) TO_ECC_64(0, 0, 0, 0, a, b, c, d)
11 # define TO_ECC_24(a, b, c) TO_ECC_64(0, 0, 0, 0, 0, a, b, c)
12 # define TO_ECC_16(a, b) TO_ECC_64(0, 0, 0, 0, 0, 0, a, b)
13 # define TO_ECC_8(a) TO_ECC_64(0, 0, 0, 0, 0, 0, 0, a)
14 # else // RADIX_BITS == 32
15 # define TO_ECC_32 BIG_ENDIAN_BYTES_TO_UINT32
16 # define TO_ECC_24(a, b, c) TO_ECC_32(0, a, b, c)
17 # define TO_ECC_16(a, b) TO_ECC_32(0, 0, a, b)
18 # define TO_ECC_8(a) TO_ECC_32(0, 0, 0, a)
19 # endif
20 #else // TPM2B_
21 # define TO_ECC_64(a, b, c, d, e, f, g, h) a, b, c, d, e, f, g, h
22 # define TO_ECC_56(a, b, c, d, e, f, g) a, b, c, d, e, f, g
23 # define TO_ECC_48(a, b, c, d, e, f) a, b, c, d, e, f
24 # define TO_ECC_40(a, b, c, d, e) a, b, c, d, e
25 # define TO_ECC_32(a, b, c, d) a, b, c, d
26 # define TO_ECC_24(a, b, c) a, b, c
27 # define TO_ECC_16(a, b) a, b
28 # define TO_ECC_8(a) a
29 #endif
30 #if USE_BN_ECC_DATA
31 #define BN_MIN_ALLOC(bytes) \
32 (BYTES_TO_CRYPT_WORDS(bytes) == 0) ? 1 : BYTES_TO_CRYPT_WORDS(bytes)
33 # define ECC_CONST(NAME, bytes, initializer) \
34 const struct { \
35 crypt_uword_t allocate, size, d[BN_MIN_ALLOC(bytes)]; \
36 } NAME = {BN_MIN_ALLOC(bytes), BYTES_TO_CRYPT_WORDS(bytes),{initializer}}
37 ECC_CONST(ECC_ZERO, 0, 0);
38 #else
39 # define ECC_CONST(NAME, bytes, initializer) \
40 const TPM2B_##bytes##_BYTE_VALUE NAME = {bytes, {initializer}}
41 TPM2B_BYTE_VALUE(1);
42 TPM2B_1_BYTE_VALUE ECC_ZERO = {1, {0}};
43
44 #endif
45
46 ECC_CONST(ECC_ONE, 1, 1);
47 #if !USE_BN_ECC_DATA
48 TPM2B_BYTE_VALUE(24);
49 #define TO_ECC_192(a, b, c) a, b, c
50 TPM2B_BYTE_VALUE(28);
51 #define TO_ECC_224(a, b, c, d) a, b, c, d
52 TPM2B_BYTE_VALUE(32);
53 #define TO_ECC_256(a, b, c, d) a, b, c, d
54 TPM2B_BYTE_VALUE(48);
55 #define TO_ECC_384(a, b, c, d, e, f) a, b, c, d, e, f
56 TPM2B_BYTE_VALUE(66);
57 #define TO_ECC_528(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i
58 TPM2B_BYTE_VALUE(80);
59 #define TO_ECC_640(a, b, c, d, e, f, g, h, i, j) a, b, c, d, e, f, g, h, i, j
60 #else
61 #define TO_ECC_192(a, b, c) c, b, a
62 #define TO_ECC_224(a, b, c, d) d, c, b, a
63 #define TO_ECC_256(a, b, c, d) d, c, b, a
64 #define TO_ECC_384(a, b, c, d, e, f) f, e, d, c, b, a
65 #define TO_ECC_528(a, b, c, d, e, f, g, h, i) i, h, g, f, e, d, c, b, a
66 #define TO_ECC_640(a, b, c, d, e, f, g, h, i, j) j, i, h, g, f, e, d, c, b, a
67 #endif // !USE_BN_ECC_DATA
68 #if ECC_NIST_P192
69 ECC_CONST(NIST_P192_p, 24, TO_ECC_192(
70 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
71 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE),
72 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
73 ECC_CONST(NIST_P192_a, 24, TO_ECC_192(
74 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
75 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE),
76 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC)));
77 ECC_CONST(NIST_P192_b, 24, TO_ECC_192(
78 TO_ECC_64(0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C, 0x80, 0xE7),
79 TO_ECC_64(0x0F, 0xA7, 0xE9, 0xAB, 0x72, 0x24, 0x30, 0x49),
80 TO_ECC_64(0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46, 0xB9, 0xB1)));
81 ECC_CONST(NIST_P192_gX, 24, TO_ECC_192(
82 TO_ECC_64(0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6),
83 TO_ECC_64(0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00),
84 TO_ECC_64(0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12)));
85 ECC_CONST(NIST_P192_gY, 24, TO_ECC_192(
86 TO_ECC_64(0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78),
87 TO_ECC_64(0x63, 0x10, 0x11, 0xED, 0x6B, 0x24, 0xCD, 0xD5),
88 TO_ECC_64(0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11)));
89 ECC_CONST(NIST_P192_n, 24, TO_ECC_192(
90 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
91 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36),
92 TO_ECC_64(0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31)));
93 #define NIST_P192_h ECC_ONE
94 #define NIST_P192_gZ ECC_ONE
95 #if USE_BN_ECC_DATA
96 const ECC_CURVE_DATA NIST_P192 = {
97 (bigNum)&NIST_P192_p, (bigNum)&NIST_P192_n, (bigNum)&NIST_P192_h,
98 (bigNum)&NIST_P192_a, (bigNum)&NIST_P192_b,
99 {(bigNum)&NIST_P192_gX, (bigNum)&NIST_P192_gY, (bigNum)&NIST_P192_gZ}};
100 #else
101 const ECC_CURVE_DATA NIST_P192 = {
102 &NIST_P192_p.b, &NIST_P192_n.b, &NIST_P192_h.b,
103 &NIST_P192_a.b, &NIST_P192_b.b,
104 {&NIST_P192_gX.b, &NIST_P192_gY.b, &NIST_P192_gZ.b}};
105
106 #endif // USE_BN_ECC_DATA
107
108 #endif // ECC_NIST_P192
109
110
111 #if ECC_NIST_P224
112 ECC_CONST(NIST_P224_p, 28, TO_ECC_224(
113 TO_ECC_32(0xFF, 0xFF, 0xFF, 0xFF),
114 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
115 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00),
116 TO_ECC_64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)));
117 ECC_CONST(NIST_P224_a, 28, TO_ECC_224(
378
379 #endif // ECC_BN_P256
380
381
382 #if ECC_BN_P638
383 ECC_CONST(BN_P638_p, 80, TO_ECC_640(
384 TO_ECC_64(0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D),
385 TO_ECC_64(0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3),
386 TO_ECC_64(0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E),
387 TO_ECC_64(0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F),
388 TO_ECC_64(0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55),
389 TO_ECC_64(0xC0, 0x00, 0x86, 0x52, 0x00, 0x21, 0xE5, 0x5B),
390 TO_ECC_64(0xFF, 0xFF, 0xF5, 0x1F, 0xFF, 0xF4, 0xEB, 0x80),
391 TO_ECC_64(0x00, 0x00, 0x00, 0x4C, 0x80, 0x01, 0x5A, 0xCD),
392 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xE0),
393 TO_ECC_64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67)));
394 #define BN_P638_a ECC_ZERO
395 ECC_CONST(BN_P638_b, 2, TO_ECC_16(0x01,0x01));
396 ECC_CONST(BN_P638_gX, 80, TO_ECC_640(
397 TO_ECC_64(0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D),
398 TO_ECC_64(0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3),
399 TO_ECC_64(0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E),
400 TO_ECC_64(0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F),
401 TO_ECC_64(0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55),
402 TO_ECC_64(0xC0, 0x00, 0x86, 0x52, 0x00, 0x21, 0xE5, 0x5B),
403 TO_ECC_64(0xFF, 0xFF, 0xF5, 0x1F, 0xFF, 0xF4, 0xEB, 0x80),
404 TO_ECC_64(0x00, 0x00, 0x00, 0x4C, 0x80, 0x01, 0x5A, 0xCD),
405 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xE0),
406 TO_ECC_64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66)));
407 ECC_CONST(BN_P638_gY, 1, TO_ECC_8(0x10));
408 ECC_CONST(BN_P638_n, 80, TO_ECC_640(
409 TO_ECC_64(0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D),
410 TO_ECC_64(0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3),
411 TO_ECC_64(0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E),
412 TO_ECC_64(0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F),
413 TO_ECC_64(0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55),
414 TO_ECC_64(0x60, 0x00, 0x86, 0x55, 0x00, 0x21, 0xE5, 0x55),
415 TO_ECC_64(0xFF, 0xFF, 0xF5, 0x4F, 0xFF, 0xF4, 0xEA, 0xC0),
416 TO_ECC_64(0x00, 0x00, 0x00, 0x49, 0x80, 0x01, 0x54, 0xD9),
417 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xA0),
418 TO_ECC_64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61)));
419 #define BN_P638_h ECC_ONE
420 #define BN_P638_gZ ECC_ONE
421 #if USE_BN_ECC_DATA
422 const ECC_CURVE_DATA BN_P638 = {
423 (bigNum)&BN_P638_p, (bigNum)&BN_P638_n, (bigNum)&BN_P638_h,
424 (bigNum)&BN_P638_a, (bigNum)&BN_P638_b,
425 {(bigNum)&BN_P638_gX, (bigNum)&BN_P638_gY, (bigNum)&BN_P638_gZ}};
426 #else
427 const ECC_CURVE_DATA BN_P638 = {
428 &BN_P638_p.b, &BN_P638_n.b, &BN_P638_h.b,
429 &BN_P638_a.b, &BN_P638_b.b,
430 {&BN_P638_gX.b, &BN_P638_gY.b, &BN_P638_gZ.b}};
431
432 #endif // USE_BN_ECC_DATA
433
434 #endif // ECC_BN_P638
435
436
437 #if ECC_SM2_P256
438 ECC_CONST(SM2_P256_p, 32, TO_ECC_256(
439 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF),
440 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
441 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00),
442 TO_ECC_64(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
508 CURVE_NAME("NIST_P224")}
509 # undef comma
510 # define comma ,
511 #endif // ECC_NIST_P224
512 #if ECC_NIST_P256
513 comma
514 {TPM_ECC_NIST_P256,
515 256,
516 {ALG_KDF1_SP800_56A_VALUE, {{ALG_SHA256_VALUE}}},
517 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
518 &NIST_P256,
519 OID_ECC_NIST_P256
520 CURVE_NAME("NIST_P256")}
521 # undef comma
522 # define comma ,
523 #endif // ECC_NIST_P256
524 #if ECC_NIST_P384
525 comma
526 {TPM_ECC_NIST_P384,
527 384,
528 {ALG_KDF1_SP800_56A_VALUE, {{ALG_SHA384_VALUE}}},
529 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
530 &NIST_P384,
531 OID_ECC_NIST_P384
532 CURVE_NAME("NIST_P384")}
533 # undef comma
534 # define comma ,
535 #endif // ECC_NIST_P384
536 #if ECC_NIST_P521
537 comma
538 {TPM_ECC_NIST_P521,
539 521,
540 {ALG_KDF1_SP800_56A_VALUE, {{ALG_SHA512_VALUE}}},
541 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
542 &NIST_P521,
543 OID_ECC_NIST_P521
544 CURVE_NAME("NIST_P521")}
545 # undef comma
546 # define comma ,
547 #endif // ECC_NIST_P521
548 #if ECC_BN_P256
549 comma
550 {TPM_ECC_BN_P256,
551 256,
552 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
553 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
554 &BN_P256,
555 OID_ECC_BN_P256
556 CURVE_NAME("BN_P256")}
557 # undef comma
558 # define comma ,
559 #endif // ECC_BN_P256
560 #if ECC_BN_P638
561 comma
562 {TPM_ECC_BN_P638,
563 638,
564 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
565 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
566 &BN_P638,
567 OID_ECC_BN_P638
568 CURVE_NAME("BN_P638")}
569 # undef comma
570 # define comma ,
571 #endif // ECC_BN_P638
572 #if ECC_SM2_P256
573 comma
574 {TPM_ECC_SM2_P256,
575 256,
576 {ALG_KDF1_SP800_56A_VALUE, {{ALG_SM3_256_VALUE}}},
577 {ALG_NULL_VALUE, {{ALG_NULL_VALUE}}},
578 &SM2_P256,
579 OID_ECC_SM2_P256
580 CURVE_NAME("SM2_P256")}
581 # undef comma
582 # define comma ,
583 #endif // ECC_SM2_P256
584 };
585 #endif // TPM_ALG_ECC
10.2.9 CryptDes.c
10.2.9.1 Introduction
1 #include "Tpm.h"
2 #if ALG_TDES
3 #define DES_NUM_WEAK 64
4 const UINT64 DesWeakKeys[DES_NUM_WEAK] = {
5 0x0101010101010101ULL, 0xFEFEFEFEFEFEFEFEULL,
6 0xE0E0E0E0F1F1F1F1ULL, 0x1F1F1F1F0E0E0E0EULL,
7 0x011F011F010E010EULL, 0x1F011F010E010E01ULL,
8 0x01E001E001F101F1ULL, 0xE001E001F101F101ULL,
9 0x01FE01FE01FE01FEULL, 0xFE01FE01FE01FE01ULL,
10 0x1FE01FE00EF10EF1ULL, 0xE01FE01FF10EF10EULL,
11 0x1FFE1FFE0EFE0EFEULL, 0xFE1FFE1FFE0EFE0EULL,
12 0xE0FEE0FEF1FEF1FEULL, 0xFEE0FEE0FEF1FEF1ULL,
13 0x01011F1F01010E0EULL, 0x1F1F01010E0E0101ULL,
14 0xE0E01F1FF1F10E0EULL, 0x0101E0E00101F1F1ULL,
15 0x1F1FE0E00E0EF1F1ULL, 0xE0E0FEFEF1F1FEFEULL,
16 0x0101FEFE0101FEFEULL, 0x1F1FFEFE0E0EFEFEULL,
17 0xE0FE011FF1FE010EULL, 0x011F1F01010E0E01ULL,
18 0x1FE001FE0EF101FEULL, 0xE0FE1F01F1FE0E01ULL,
19 0x011FE0FE010EF1FEULL, 0x1FE0E01F0EF1F10EULL,
20 0xE0FEFEE0F1FEFEF1ULL, 0x011FFEE0010EFEF1ULL,
21 0x1FE0FE010EF1FE01ULL, 0xFE0101FEFE0101FEULL,
22 0x01E01FFE01F10EFEULL, 0x1FFE01E00EFE01F1ULL,
23 0xFE011FE0FE010EF1ULL, 0xFE01E01FFE01F10EULL,
24 0x1FFEE0010EFEF101ULL, 0xFE1F01E0FE0E01F1ULL,
25 0x01E0E00101F1F101ULL, 0x1FFEFE1F0EFEFE0EULL,
26 0xFE1FE001FE0EF101ULL, 0x01E0FE1F01F1FE0EULL,
27 0xE00101E0F10101F1ULL, 0xFE1F1FFEFE0E0EFEULL,
28 0x01FE1FE001FE0EF1ULL, 0xE0011FFEF1010EFEULL,
29 0xFEE0011FFEF1010EULL, 0x01FEE01F01FEF10EULL,
30 0xE001FE1FF101FE0EULL, 0xFEE01F01FEF10E01ULL,
31 0x01FEFE0101FEFE01ULL, 0xE01F01FEF10E01FEULL,
32 0xFEE0E0FEFEF1F1FEULL, 0x1F01011F0E01010EULL,
33 0xE01F1FE0F10E0EF1ULL, 0xFEFE0101FEFE0101ULL,
34 0x1F01E0FE0E01F1FEULL, 0xE01FFE01F10EFE01ULL,
35 0xFEFE1F1FFEFE0E0EULL, 0x1F01FEE00E01FEF1ULL,
36 0xE0E00101F1F10101ULL, 0xFEFEE0E0FEFEF1F1ULL};
37
38 //*** CryptSetOddByteParity()
39 // This function sets the per byte parity of a 64-bit value. The least-significant
40 // bit is of each byte is replaced with the odd parity of the other 7 bits in the
41 // byte. With odd parity, no byte will ever be 0x00.
42 UINT64
43 CryptSetOddByteParity(
44 UINT64 k
45 )
46 {
47 #define PMASK 0x0101010101010101ULL
48 UINT64 out;
49 k |= PMASK; // set the parity bit
50 out = k;
51 k ^= k >> 4;
52 k ^= k >> 2;
53 k ^= k >> 1;
10.2.9.2.1 CryptDesIsWeakKey()
Check to see if a DES key is on the list of weak, semi-weak, or possibly weak keys.
59 static BOOL
60 CryptDesIsWeakKey(
61 UINT64 k
62 )
63 {
64 int i;
65 //
66 for(i = 0; i < DES_NUM_WEAK; i++)
67 {
68 if(k == DesWeakKeys[i])
69 return TRUE;
70 }
71 return FALSE;
72 }
10.2.9.2.2 CryptDesValidateKey()
Function to check to see if the input key is a valid DES key where the definition of valid is that none of the
elements are on the list of weak, semi-weak, or possibly weak keys; and that for two keys, K1!=K2, and
for three keys that K1!=K2 and K2!=K3.
73 BOOL
74 CryptDesValidateKey(
75 TPM2B_SYM_KEY *desKey // IN: key to validate
76 )
77 {
78 UINT64 k[3];
79 int i;
80 int keys = (desKey->t.size + 7) / 8;
81 BYTE *pk = desKey->t.buffer;
82 BOOL ok;
83 //
84 // Note: 'keys' is the number of keys, not the maximum index for 'k'
85 ok = ((keys == 2) || (keys == 3)) && ((desKey->t.size % 8) == 0);
86 for(i = 0; ok && i < keys; pk += 8, i++)
87 {
88 k[i] = CryptSetOddByteParity(BYTE_ARRAY_TO_UINT64(pk));
89 ok = !CryptDesIsWeakKey(k[i]);
90 }
91 ok = ok && k[0] != k[1];
92 if(keys == 3)
93 ok = ok && k[1] != k[2];
94 return ok;
95 }
10.2.9.2.3 CryptGenerateKeyDes()
This function is used to create a DES key of the appropriate size. The key will have odd parity in the
bytes.
96 TPM_RC
97 CryptGenerateKeyDes(
98 TPMT_PUBLIC *publicArea, // IN/OUT: The public area template
99 // for the new key.
100 TPMT_SENSITIVE *sensitive, // OUT: sensitive area
101 RAND_STATE *rand // IN: the "entropy" source for
102 )
103 {
104
105 // Assume that the publicArea key size has been validated and is a supported
106 // number of bits.
107 sensitive->sensitive.sym.t.size =
108 BITS_TO_BYTES(publicArea->parameters.symDetail.sym.keyBits.sym);
109 do
110 {
111 BYTE *pK = sensitive->sensitive.sym.t.buffer;
112 int i = (sensitive->sensitive.sym.t.size + 7) / 8;
113 // Use the random number generator to generate the required number of bits
114 if(DRBG_Generate(rand, pK, sensitive->sensitive.sym.t.size) == 0)
115 return TPM_RC_NO_RESULT;
116 for(; i > 0; pK += 8, i--)
117 {
118 UINT64 k = BYTE_ARRAY_TO_UINT64(pK);
119 k = CryptSetOddByteParity(k);
120 UINT64_TO_BYTE_ARRAY(k, pK);
121 }
122 } while(!CryptDesValidateKey(&sensitive->sensitive.sym));
123 return TPM_RC_SUCCESS;
124 }
125 #endif
10.2.10 CryptEccKeyExchange.c
10.2.10.1 Introduction
This file contains the functions that are used for the two-phase, ECC, key-exchange protocols
1 #include "Tpm.h"
2 #if CC_ZGen_2Phase == YES
10.2.10.2 Functions
3 #if ALG_ECMQV
10.2.10.2.1 avf1()
This function does the associated value computation required by MQV key exchange. Process:
Convert xQ to an integer xqi using the convention specified in Appendix C.3.
Calculate xqm = xqi mod 2^ceil(f/2) (where f = ceil(log2(n)).
Calculate the associate value function avf(Q) = xqm + 2ceil(f / 2) Always returns TRUE(1).
4 static BOOL
5 avf1(
6 bigNum bnX, // IN/OUT: the reduced value
7 bigNum bnN // IN: the order of the curve
8 )
9 {
10 // compute f = 2^(ceil(ceil(log2(n)) / 2))
11 int f = (BnSizeInBits(bnN) + 1) / 2;
12 // x' = 2^f + (x mod 2^f)
13 BnMaskBits(bnX, f); // This is mod 2*2^f but it doesn't matter because
14 // the next operation will SET the extra bit anyway
15 BnSetBit(bnX, f);
16 return TRUE;
17 }
10.2.10.2.2 C_2_2_MQV()
This function performs the key exchange defined in SP800-56A 6.1.1.4 Full MQV, C(2, 2, ECC MQV).
CAUTION: Implementation of this function may require use of essential claims in patents not owned by
TCG members.
Points QsB and QeB are required to be on the curve of inQsA. The function will fail, possibly
catastrophically, if this is not the case.
18 static TPM_RC
19 C_2_2_MQV(
20 TPMS_ECC_POINT *outZ, // OUT: the computed point
21 TPM_ECC_CURVE curveId, // IN: the curve for the computations
22 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
23 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
24 TPMS_ECC_POINT *QsB, // IN: static public party B key
25 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
26 )
27 {
28 CURVE_INITIALIZED(E, curveId);
29 const ECC_CURVE_DATA *C;
30 POINT(pQeA);
31 POINT_INITIALIZED(pQeB, QeB);
32 POINT_INITIALIZED(pQsB, QsB);
33 ECC_NUM(bnTa);
34 ECC_INITIALIZED(bnDeA, deA);
35 ECC_INITIALIZED(bnDsA, dsA);
36 ECC_NUM(bnN);
37 ECC_NUM(bnXeB);
38 TPM_RC retVal;
39 //
40 // Parameter checks
41 if(E == NULL)
42 ERROR_RETURN(TPM_RC_VALUE);
43 pAssert(outZ != NULL && pQeB != NULL && pQsB != NULL && deA != NULL
44 && dsA != NULL);
45 C = AccessCurveData(E);
46 // Process:
47 // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
48 // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
49 // 3. If P = O, output an error indicator.
50 // 4. Z=xP, where xP is the x-coordinate of P.
51
52 // Compute the public ephemeral key pQeA = [de,A]G
53 if((retVal = BnPointMult(pQeA, CurveGetG(C), bnDeA, NULL, NULL, E))
54 != TPM_RC_SUCCESS)
55 goto Exit;
56
57 // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
58 // tA := (ds,A + de,A avf(Xe,A)) mod n (3)
59 // Compute 'tA' = ('deA' + 'dsA' avf('XeA')) mod n
60 // Ta = avf(XeA);
61 BnCopy(bnTa, pQeA->x);
62 avf1(bnTa, bnN);
63 // do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n
64 BnModMult(bnTa, bnDsA, bnTa, bnN);
65 // now Ta = deA + Ta mod n = deA + dsA * avf(XeA) mod n
66 BnAdd(bnTa, bnTa, bnDeA);
67 BnMod(bnTa, bnN);
68
69 // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
70 // Put this in because almost every case of h is == 1 so skip the call when
71 // not necessary.
72 if(!BnEqualWord(CurveGetCofactor(C), 1))
73 // Cofactor is not 1 so compute Ta := Ta * h mod n
74 BnModMult(bnTa, bnTa, CurveGetCofactor(C), CurveGetOrder(C));
75
76 // Now that 'tA' is (h * 'tA' mod n)
77 // 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B).
78
79 // first, compute XeB = avf(XeB)
80 avf1(bnXeB, bnN);
81
82 // QsB := [XeB]QsB
83 BnPointMult(pQsB, pQsB, bnXeB, NULL, NULL, E);
84 BnEccAdd(pQeB, pQeB, pQsB, E);
85
86 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
87 // If the result is not the point at infinity, return QeB
88 BnPointMult(pQeB, pQeB, bnTa, NULL, NULL, E);
89 if(BnEqualZero(pQeB->z))
90 ERROR_RETURN(TPM_RC_NO_RESULT);
91 // Convert BIGNUM E to TPM2B E
10.2.10.2.3 C_2_2_ECDH()
This function performs the two phase key exchange defined in SP800-56A, 6.1.1.2 Full Unified Model,
C(2, 2, ECC CDH).
99 static TPM_RC
100 C_2_2_ECDH(
101 TPMS_ECC_POINT *outZs, // OUT: Zs
102 TPMS_ECC_POINT *outZe, // OUT: Ze
103 TPM_ECC_CURVE curveId, // IN: the curve for the computations
104 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
105 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
106 TPMS_ECC_POINT *QsB, // IN: static public party B key
107 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
108 )
109 {
110 CURVE_INITIALIZED(E, curveId);
111 ECC_INITIALIZED(bnAs, dsA);
112 ECC_INITIALIZED(bnAe, deA);
113 POINT_INITIALIZED(ecBs, QsB);
114 POINT_INITIALIZED(ecBe, QeB);
115 POINT(ecZ);
116 TPM_RC retVal;
117 //
118 // Parameter checks
119 if(E == NULL)
120 ERROR_RETURN(TPM_RC_CURVE);
121 pAssert(outZs != NULL && dsA != NULL && deA != NULL && QsB != NULL
122 && QeB != NULL);
123
124 // Do the point multiply for the Zs value ([dsA]QsB)
125 retVal = BnPointMult(ecZ, ecBs, bnAs, NULL, NULL, E);
126 if(retVal == TPM_RC_SUCCESS)
127 {
128 // Convert the Zs value.
129 BnPointTo2B(outZs, ecZ, E);
130 // Do the point multiply for the Ze value ([deA]QeB)
131 retVal = BnPointMult(ecZ, ecBe, bnAe, NULL, NULL, E);
132 if(retVal == TPM_RC_SUCCESS)
133 BnPointTo2B(outZe, ecZ, E);
134 }
135 Exit:
136 CURVE_FREE(E);
137 return retVal;
138 }
10.2.10.2.4 CryptEcc2PhaseKeyExchange()
This function is the dispatch routine for the EC key exchange functions that use two ephemeral and two
static keys.
10.2.10.2.5 ComputeWForSM2()
10.2.10.2.6 avfSm2()
This function does the associated value computation required by SM2 key exchange. This is different
from the avf() in the international standards because it returns a value that is half the size of the value
returned by the standard avf(). For example, if n is 15, Ws (w in the standard) is 2 but the W here is 1.
This means that an input value of 14 (1110b) would return a value of 110b with the standard but 10b with
the scheme in SM2.
10.2.10.2.7 SM2KeyExchange()
This function performs the key exchange defined in SM2. The first step is to compute tA = (dsA + deA
avf(Xe,A)) mod n Then, compute the Z value from outZ = (h tA mod n) (QsA + [avf(QeB.x)](QeB)). The
function will compute the ephemeral public key from the ephemeral private key. All points are required to
be on the curve of inQsA. The function will fail catastrophically if this is not the case
234 ERROR_RETURN(TPM_RC_CURVE);
235 C = AccessCurveData(E);
236 pAssert(outZ != NULL && dsA != NULL && deA != NULL && QsB != NULL
237 && QeB != NULL);
238
239 // Compute the value for w
240 w = ComputeWForSM2(E);
241
242 // Compute the public ephemeral key pQeA = [de,A]G
243 if(!BnEccModMult(QeA, CurveGetG(C), deA, E))
244 goto Exit;
245
246 // tA := (ds,A + de,A avf(Xe,A)) mod n (3)
247 // Compute 'tA' = ('dsA' + 'deA' avf('XeA')) mod n
248 // Ta = avf(XeA);
249 // do Ta = de,A * Ta = deA * avf(XeA)
250 BnMult(Ta, deA, avfSm2(QeA->x, w));
251 // now Ta = dsA + Ta = dsA + deA * avf(XeA)
252 BnAdd(Ta, dsA, Ta);
253 BnMod(Ta, CurveGetOrder(C));
254
255 // outZ = [h tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4)
256 // Put this in because almost every case of h is == 1 so skip the call when
257 // not necessary.
258 if(!BnEqualWord(CurveGetCofactor(C), 1))
259 // Cofactor is not 1 so compute Ta := Ta * h mod n
260 BnModMult(Ta, Ta, CurveGetCofactor(C), CurveGetOrder(C));
261 // Now that 'tA' is (h * 'tA' mod n)
262 // 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)).
263 BnCopy(XeB, QeB->x);
264 if(!BnEccModMult2(Z, QsB, One, QeB, avfSm2(XeB, w), E))
265 goto Exit;
266 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
267 if(!BnEccModMult(Z, Z, Ta, E))
268 goto Exit;
269 // Convert BIGNUM E to TPM2B E
270 BnPointTo2B(outZ, Z, E);
271 retVal = TPM_RC_SUCCESS;
272 Exit:
273 CURVE_FREE(E);
274 return retVal;
275 }
276 #endif
277 #endif // CC_ZGen_2Phase
10.2.11 CryptEccMain.c
1 #include "Tpm.h"
2 #if ALG_ECC
This version requires that the new format for ECC data be used
3 #if !USE_BN_ECC_DATA
4 #error "Need to SET USE_BN_ECC_DATA to YES in Implementaion.h"
5 #endif
10.2.11.2 Functions
6 #if SIMULATION
7 void
8 EccSimulationEnd(
9 void
10 )
11 {
12 #if SIMULATION
13 // put things to be printed at the end of the simulation here
14 #endif
15 }
16 #endif // SIMULATION
10.2.11.2.1 CryptEccInit()
17 BOOL
18 CryptEccInit(
19 void
20 )
21 {
22 return TRUE;
23 }
10.2.11.2.2 CryptEccStartup()
24 BOOL
25 CryptEccStartup(
26 void
27 )
28 {
29 return TRUE;
30 }
10.2.11.2.3 ClearPoint2B(generic
31 void
32 ClearPoint2B(
33 TPMS_ECC_POINT *p // IN: the point
34 )
35 {
36 if(p != NULL)
37 {
38 p->x.t.size = 0;
39 p->y.t.size = 0;
40 }
41 }
10.2.11.2.4 CryptEccGetParametersByCurveId()
This function returns a pointer to the curve data that is associated with the indicated curveId. If there is no
curve with the indicated ID, the function returns NULL. This function is in this module so that it can be
called by GetCurve() data.
10.2.11.2.5 CryptEccGetKeySizeForCurve()
This function returns the key size in bits of the indicated curve.
55 LIB_EXPORT UINT16
56 CryptEccGetKeySizeForCurve(
57 TPM_ECC_CURVE curveId // IN: the curve
58 )
59 {
60 const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
61 UINT16 keySizeInBits;
62 //
63 keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0;
64 return keySizeInBits;
65 }
10.2.11.2.6 GetCurveData()
This function returns the a pointer for the parameter data associated with a curve.
66 const ECC_CURVE_DATA *
67 GetCurveData(
68 TPM_ECC_CURVE curveId // IN: the curveID
69 )
70 {
71 const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
10.2.11.2.7 CryptEccGetOID()
74 const BYTE *
75 CryptEccGetOID(
76 TPM_ECC_CURVE curveId
77 )
78 {
79 const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
80 return (curve != NULL) ? curve->OID : NULL;
81 }
10.2.11.2.8 CryptEccGetCurveByIndex()
This function returns the number of the i-th implemented curve. The normal use would be to call this
function with i starting at 0. When the i is greater than or equal to the number of implemented curves,
TPM_ECC_NONE is returned.
82 LIB_EXPORT TPM_ECC_CURVE
83 CryptEccGetCurveByIndex(
84 UINT16 i
85 )
86 {
87 if(i >= ECC_CURVE_COUNT)
88 return TPM_ECC_NONE;
89 return eccCurves[i].curveId;
90 }
10.2.11.2.9 CryptEccGetParameter()
This function returns an ECC curve parameter. The parameter is selected by a single character
designator from the set of "PNABXYH".
91 LIB_EXPORT BOOL
92 CryptEccGetParameter(
93 TPM2B_ECC_PARAMETER *out, // OUT: place to put parameter
94 char p, // IN: the parameter selector
95 TPM_ECC_CURVE curveId // IN: the curve id
96 )
97 {
98 const ECC_CURVE_DATA *curve = GetCurveData(curveId);
99 bigConst parameter = NULL;
100
101 if(curve != NULL)
102 {
103 switch(p)
104 {
105 case 'p':
106 parameter = CurveGetPrime(curve);
107 break;
108 case 'n':
109 parameter = CurveGetOrder(curve);
110 break;
10.2.11.2.10 CryptCapGetECCCurve()
135 TPMI_YES_NO
136 CryptCapGetECCCurve(
137 TPM_ECC_CURVE curveID, // IN: the starting ECC curve
138 UINT32 maxCount, // IN: count of returned curves
139 TPML_ECC_CURVE *curveList // OUT: ECC curve list
140 )
141 {
142 TPMI_YES_NO more = NO;
143 UINT16 i;
144 UINT32 count = ECC_CURVE_COUNT;
145 TPM_ECC_CURVE curve;
146
147 // Initialize output property list
148 curveList->count = 0;
149
150 // The maximum count of curves we may return is MAX_ECC_CURVES
151 if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES;
152
153 // Scan the eccCurveValues array
154 for(i = 0; i < count; i++)
155 {
156 curve = CryptEccGetCurveByIndex(i);
157 // If curveID is less than the starting curveID, skip it
158 if(curve < curveID)
159 continue;
160 if(curveList->count < maxCount)
161 {
162 // If we have not filled up the return list, add more curves to
163 // it
10.2.11.2.11 CryptGetCurveSignScheme()
10.2.11.2.12 CryptGenerateR()
This function computes the commit random value for a split signing scheme.
If c is NULL, it indicates that r is being generated for TPM2_Commit(). If c is not NULL, the TPM will
validate that the gr.commitArray bit associated with the input value of c is SET. If not, the TPM returns
FALSE and no r value is generated.
189 BOOL
190 CryptGenerateR(
191 TPM2B_ECC_PARAMETER *r, // OUT: the generated random value
192 UINT16 *c, // IN/OUT: count value.
193 TPMI_ECC_CURVE curveID, // IN: the curve for the value
194 TPM2B_NAME *name // IN: optional name of a key to
195 // associate with 'r'
196 )
197 {
198 // This holds the marshaled g_commitCounter.
199 TPM2B_TYPE(8B, 8);
200 TPM2B_8B cntr = {{8,{0}}};
201 UINT32 iterations;
202 TPM2B_ECC_PARAMETER n;
203 UINT64 currentCount = gr.commitCounter;
204 UINT16 t1;
205 //
206 if(!CryptEccGetParameter(&n, 'n', curveID))
10.2.11.2.13 CryptCommit()
This function is called when the count value is committed. The gr.commitArray value associated with the
current count value is SET and g_commitCounter is incremented. The low-order 16 bits of old value of the
counter is returned.
266 UINT16
267 CryptCommit(
268 void
269 )
270 {
271 UINT16 oldCount = (UINT16)gr.commitCounter;
272 gr.commitCounter++;
273 SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray);
274 return oldCount;
275 }
10.2.11.2.14 CryptEndCommit()
This function is called when the signing operation using the committed value is completed. It clears the
gr.commitArray bit associated with the count value so that it can't be used again.
276 void
277 CryptEndCommit(
278 UINT16 c // IN: the counter value of the commitment
279 )
280 {
281 ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray));
282 }
10.2.11.2.15 CryptEccGetParameters()
This function returns the ECC parameter details of the given curve.
283 BOOL
284 CryptEccGetParameters(
285 TPM_ECC_CURVE curveId, // IN: ECC curve ID
286 TPMS_ALGORITHM_DETAIL_ECC *parameters // OUT: ECC parameters
287 )
288 {
289 const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
290 const ECC_CURVE_DATA *data;
291 BOOL found = curve != NULL;
292
293 if(found)
294 {
295 data = curve->curveData;
296 parameters->curveID = curve->curveId;
297 parameters->keySize = curve->keySizeBits;
298 parameters->kdf = curve->kdf;
299 parameters->sign = curve->sign;
300 // BnTo2B(data->prime, ¶meters->p.b, 0);
301 BnTo2B(data->prime, ¶meters->p.b, parameters->p.t.size);
302 BnTo2B(data->a, ¶meters->a.b, 0);
303 BnTo2B(data->b, ¶meters->b.b, 0);
304 BnTo2B(data->base.x, ¶meters->gX.b, parameters->p.t.size);
10.2.11.2.16 BnGetCurvePrime()
This function is used to get just the prime modulus associated with a curve.
10.2.11.2.17 BnGetCurveOrder()
10.2.11.2.18 BnIsOnCurve()
329 BOOL
330 BnIsOnCurve(
331 pointConst Q,
332 const ECC_CURVE_DATA *C
333 )
334 {
335 BN_VAR(right, (MAX_ECC_KEY_BITS * 3));
336 BN_VAR(left, (MAX_ECC_KEY_BITS * 2));
337 bigConst prime = CurveGetPrime(C);
338 //
339 // Show that point is on the curve y^2 = x^3 + ax + b;
340 // Or y^2 = x(x^2 + a) + b
341 // y^2
342 BnMult(left, Q->y, Q->y);
343
344 BnMod(left, prime);
345 // x^2
346 BnMult(right, Q->x, Q->x);
347
348 // x^2 + a
349 BnAdd(right, right, CurveGet_a(C));
350
10.2.11.2.19 BnIsValidPrivateEcc()
364 BOOL
365 BnIsValidPrivateEcc(
366 bigConst x, // IN: private key to check
367 bigCurve E // IN: the curve to check
368 )
369 {
370 BOOL retVal;
371 retVal = (!BnEqualZero(x)
372 && (BnUnsignedCmp(x, CurveGetOrder(AccessCurveData(E))) < 0));
373 return retVal;
374 }
375 LIB_EXPORT BOOL
376 CryptEccIsValidPrivateKey(
377 TPM2B_ECC_PARAMETER *d,
378 TPM_ECC_CURVE curveId
379 )
380 {
381 BN_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d);
382 return !BnEqualZero(bnD) && (BnUnsignedCmp(bnD, BnGetCurveOrder(curveId)) < 0);
383 }
10.2.11.2.20 BnPointMul()
This function does a point multiply of the form R = [d]S + [u]Q where the parameters are bigNum values.
If S is NULL and d is not NULL, then it computes R = [d]G + [u]Q or just R = [d]G if u and Q are NULL. If
skipChecks is TRUE, then the function will not verify that the inputs are correct for the domain. This would
be the case when the values were created by the CryptoEngine() code. It will return
TPM_RC_NO_RESULT if the resulting point is the point at infinity.
384 TPM_RC
385 BnPointMult(
386 bigPoint R, // OUT: computed point
387 pointConst S, // IN: optional point to multiply by 'd'
388 bigConst d, // IN: scalar for [d]S or [d]G
389 pointConst Q, // IN: optional second point
390 bigConst u, // IN: optional second scalar
10.2.11.2.21 BnEccGetPrivate()
This function gets random values that are the size of the key plus 64 bits. The value is reduced (mod (q -
1)) and incremented by 1 (q is the order of the curve. This produces a value (d) such that 1 <= d < q. This
is the method of FIPS 186-4 Section B.4.1 "Key Pair Generation Using Extra Random Bits".
434 BOOL
435 BnEccGetPrivate(
436 bigNum dOut, // OUT: the qualified random value
437 const ECC_CURVE_DATA *C, // IN: curve for which the private key
438 // needs to be appropriate
439 RAND_STATE *rand // IN: state for DRBG
440 )
441 {
10.2.11.2.22 BnEccGenerateKeyPair()
This function gets a private scalar from the source of random bits and does the point multiply to get the
public key.
455 BOOL
456 BnEccGenerateKeyPair(
457 bigNum bnD, // OUT: private scalar
458 bn_point_t *ecQ, // OUT: public point
459 bigCurve E, // IN: curve for the point
460 RAND_STATE *rand // IN: DRBG state to use
461 )
462 {
463 BOOL OK = FALSE;
464 // Get a private scalar
465 OK = BnEccGetPrivate(bnD, AccessCurveData(E), rand);
466
467 // Do a point multiply
468 OK = OK && BnEccModMult(ecQ, NULL, bnD, E);
469 if(!OK)
470 BnSetWord(ecQ->z, 0);
471 else
472 BnSetWord(ecQ->z, 1);
473 return OK;
474 }
10.2.11.2.23 CryptEccNewKeyPair
This function creates an ephemeral ECC. It is ephemeral in that is expected that the private part of the
key will be discarded
492 if(OK)
493 {
494 BnPointTo2B(Qout, ecQ, E);
495 BnTo2B(bnD, &dOut->b, Qout->x.t.size);
496 }
497 else
498 {
499 Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0;
500 }
501 CURVE_FREE(E);
502 return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
503 }
10.2.11.2.24 CryptEccPointMultiply()
This function computes R := [dIn]G + [uIn]QIn. Where dIn and uIn are scalars, G and QIn are points on
the specified curve and G is the default generator of the curve.
The xOut and yOut parameters are optional and may be set to NULL if not used.
It is not necessary to provide uIn if QIn is specified but one of uIn and dIn must be provided. If dIn and
QIn are specified but uIn is not provided, then R = [dIn]QIn.
If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned.
The sizes of xOut and yOut' will be set to be the size of the degree of the curve
It is a fatal error if dIn and uIn are both unspecified (NULL) or if Qin or Rout is unspecified.
10.2.11.2.25 CryptEccIsPointOnCurve()
This function is used to test if a point is on a defined curve. It does this by checking that y^2 mod p = x^3
+ a*x + b mod p.
It is a fatal error if Q is not specified (is NULL).
10.2.11.2.26 CryptEccGenerateKey()
This function generates an ECC key pair based on the input parameters. This routine uses KDFa to
produce candidate numbers. The method is according to FIPS 186-3, section B.1.2 "Key Pair Generation
by Testing Candidates." According to the method in FIPS 186-3, the resulting private value d should be 1
<= d < n where n is the order of the base point.
It is a fatal error if Qout, dOut, is not provided (is NULL).
If the curve is not supported If seed is not provided, then a random number will be used for the key
562 ECC_NUM(bnD);
563 POINT(ecQ);
564 BOOL OK;
565 TPM_RC retVal;
566 //
567 TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key
568
569 // Validate parameters
570 if(E == NULL)
571 ERROR_RETURN(TPM_RC_CURVE);
572
573 publicArea->unique.ecc.x.t.size = 0;
574 publicArea->unique.ecc.y.t.size = 0;
575 sensitive->sensitive.ecc.t.size = 0;
576
577 OK = BnEccGenerateKeyPair(bnD, ecQ, E, rand);
578 if(OK)
579 {
580 BnPointTo2B(&publicArea->unique.ecc, ecQ, E);
581 BnTo2B(bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size);
582 }
583 #if FIPS_COMPLIANT
584 // See if PWCT is required
585 if(OK && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
586 {
587 ECC_NUM(bnT);
588 ECC_NUM(bnS);
589 TPM2B_DIGEST digest;
590 //
591 TEST(TPM_ALG_ECDSA);
592 digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer));
593 // Get a random value to sign using the built in DRBG state
594 DRBG_Generate(NULL, digest.t.buffer, digest.t.size);
595 if(g_inFailureMode)
596 return TPM_RC_FAILURE;
597 BnSignEcdsa(bnT, bnS, E, bnD, &digest, NULL);
598 // and make sure that we can validate the signature
599 OK = BnValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS;
600 }
601 #endif
602 retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
603 Exit:
604 CURVE_FREE(E);
605 return retVal;
606 }
607 #endif // ALG_ECC
10.2.12 CryptEccSignature.c
1 #include "Tpm.h"
2 #include "CryptEccSignature_fp.h"
3 #if ALG_ECC
10.2.12.2.1 EcdsaDigest()
Function to adjust the digest so that it is no larger than the order of the curve. This is used for ECDSA
sign and verification.
4 static bigNum
5 EcdsaDigest(
6 bigNum bnD, // OUT: the adjusted digest
7 const TPM2B_DIGEST *digest, // IN: digest to adjust
8 bigConst max // IN: value that indicates the maximum
9 // number of bits in the results
10 )
11 {
12 int bitsInMax = BnSizeInBits(max);
13 int shift;
14 //
15 if(digest == NULL)
16 BnSetWord(bnD, 0);
17 else
18 {
19 BnFromBytes(bnD, digest->t.buffer,
20 (NUMBYTES)MIN(digest->t.size, BITS_TO_BYTES(bitsInMax)));
21 shift = BnSizeInBits(bnD) - bitsInMax;
22 if(shift > 0)
23 BnShiftRight(bnD, bnD, shift);
24 }
25 return bnD;
26 }
10.2.12.2.2 BnSchnorrSign()
This contains the Schnorr signature computation. It is used by both ECDSA and Schnorr signing. The
result is computed as: [s = k + r * d (mod n)] where
s is the signature
k is a random value
r is the value to sign
d is the private EC key
n is the order of the curve
27 static TPM_RC
28 BnSchnorrSign(
29 bigNum bnS, // OUT: 's' component of the signature
10.2.12.3.1 BnSignEcdsa()
This function implements the ECDSA signing algorithm. The method is described in the comments below.
53 TPM_RC
54 BnSignEcdsa(
55 bigNum bnR, // OUT: 'r' component of the signature
56 bigNum bnS, // OUT: 's' component of the signature
57 bigCurve E, // IN: the curve used in the signature
58 // process
59 bigNum bnD, // IN: private signing key
60 const TPM2B_DIGEST *digest, // IN: the digest to sign
61 RAND_STATE *rand // IN: used in debug of signing
62 )
63 {
64 ECC_NUM(bnK);
65 ECC_NUM(bnIk);
66 BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8);
67 POINT(ecR);
68 bigConst order = CurveGetOrder(AccessCurveData(E));
69 TPM_RC retVal = TPM_RC_SUCCESS;
70 INT32 tries = 10;
71 BOOL OK = FALSE;
72 //
73 pAssert(digest != NULL);
74 // The algorithm as described in "Suite B Implementer's Guide to FIPS
75 // 186-3(ECDSA)"
76 // 1. Use one of the routines in Appendix A.2 to generate (k, k^-1), a
77 // per-message secret number and its inverse modulo n. Since n is prime,
78 // the output will be invalid only if there is a failure in the RBG.
79 // 2. Compute the elliptic curve point R = [k]G = (xR, yR) using EC scalar
80 // multiplication (see [Routines]), where G is the base point included in
81 // the set of domain parameters.
82 // 3. Compute r = xR mod n. If r = 0, then return to Step 1. 1.
83 // 4. Use the selected hash function to compute H = Hash(M).
84 // 5. Convert the bit string H to an integer e as described in Appendix B.2.
85 // 6. Compute s = (k^-1 * (e + d * r)) mod q. If s = 0, return to Step 1.2.
10.2.12.3.2 BnSignEcdaa()
189 // it will probably not be worthwhile to run the same command again because
190 // the result will still be zero. This means that the Commit command will
191 // need to be run again to get a new commit value for the signature.
192 if(retVal == TPM_RC_SUCCESS)
193 CryptEndCommit(scheme->details.ecdaa.count);
194 }
195 return retVal;
196 }
197 #endif // ALG_ECDAA
198 #if ALG_ECSCHNORR
10.2.12.3.3 SchnorrReduce()
Function to reduce a hash result if it's magnitude is too large. The size of number is set so that it has no
more bytes of significance than reference value. If the resulting number can have more bits of
significance than reference.
10.2.12.3.4 SchnorrEcc()
10.2.12.3.5 BnHexEqual()
10.2.12.3.6 BnSignEcSm2()
This function signs a digest using the method defined in SM2 Part 2. The method in the standard will add
a header to the message to be signed that is a hash of the values that define the key. This then hashed
with the message to produce a digest (e). This function signs e.
329 "94F79FB1EED2CAA55BACDB49C4E755D1"));
330 #endif
331 // if r=0 or r+k=n, return to A3;
332 if(BnEqualZero(bnR))
333 goto loop;
334 BnAdd(bnT, bnK, bnR);
335 if(BnUnsignedCmp(bnT, bnN) == 0)
336 goto loop;
337 // A6: Figure out s = ((1 + dA)^-1 (k - r dA)) mod n,
338 // if s=0, return to A3;
339 // compute t = (1+dA)^-1
340 BnAddWord(bnT, bnD, 1);
341 BnModInverse(bnT, bnT, order);
342 #ifdef _SM2_SIGN_DEBUG
343 pAssert(BnHexEqual(bnT, "79BFCF3052C80DA7B939E0C6914A18CB"
344 "B2D96D8555256E83122743A7D4F5F956"));
345 #endif
346 // compute s = t * (k - r * dA) mod n
347 BnModMult(bnS, bnR, bnD, order);
348 // k - r * dA mod n = k + n - ((r * dA) mod n)
349 BnSub(bnS, order, bnS);
350 BnAdd(bnS, bnK, bnS);
351 BnModMult(bnS, bnS, bnT, order);
352 #ifdef _SM2_SIGN_DEBUG
353 pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6"
354 "67A457872FB09EC56327A67EC7DEEBE7"));
355 #endif
356 if(BnEqualZero(bnS))
357 goto loop;
358 }
359 // A7: According to details specified in 4.2.1 in Part 1 of this document,
360 // transform the data type of r, s into bit strings, signature of message M
361 // is (r, s).
362 // This is handled by the common return code
363 #ifdef _SM2_SIGN_DEBUG
364 pAssert(BnHexEqual(bnR, "40F1EC59F793D9F49E09DCEF49130D41"
365 "94F79FB1EED2CAA55BACDB49C4E755D1"));
366 pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6"
367 "67A457872FB09EC56327A67EC7DEEBE7"));
368 #endif
369 return TPM_RC_SUCCESS;
370 }
371 #endif // ALG_SM2
10.2.12.3.7 CryptEccSign()
This function is the dispatch function for the various ECC-based signing schemes. There is a bit of
ugliness to the parameter passing. In order to test this, we sometime would like to use a deterministic
RNG so that we can get the same signatures during testing. The easiest way to do this for most schemes
is to pass in a deterministic RNG and let it return canned values during testing. There is a competing
need for a canned parameter to use in ECDAA. To accommodate both needs with minimal fuss, a special
type of RAND_STATE is defined to carry the address of the commit value. The setup and handling of this
is not very different for the caller than what was in previous versions of the code.
10.2.12.3.8 BnValidateSignatureEcdsa()
This function validates an ECDSA signature. rIn and sIn should have been checked to make sure that
they are in the range 0 < v < n
439 TPM_RC
440 BnValidateSignatureEcdsa(
441 bigNum bnR, // IN: 'r' component of the signature
442 bigNum bnS, // IN: 's' component of the signature
443 bigCurve E, // IN: the curve used in the signature
444 // process
445 bn_point_t *ecQ, // IN: the public point of the key
446 const TPM2B_DIGEST *digest // IN: the digest that was signed
447 )
448 {
449 // Make sure that the allocation for the digest is big enough for a maximum
450 // digest
451 BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8);
452 POINT(ecR);
453 ECC_NUM(bnU1);
454 ECC_NUM(bnU2);
455 ECC_NUM(bnW);
456 bigConst order = CurveGetOrder(AccessCurveData(E));
457 TPM_RC retVal = TPM_RC_SIGNATURE;
458 //
459 // Get adjusted digest
460 EcdsaDigest(bnE, digest, order);
461 // 1. If r and s are not both integers in the interval [1, n - 1], output
462 // INVALID.
463 // bnR and bnS were validated by the caller
464 // 2. Use the selected hash function to compute H0 = Hash(M0).
465 // This is an input parameter
466 // 3. Convert the bit string H0 to an integer e as described in Appendix B.2.
467 // Done at entry
468 // 4. Compute w = (s')^-1 mod n, using the routine in Appendix B.1.
469 if(!BnModInverse(bnW, bnS, order))
470 goto Exit;
471 // 5. Compute u1 = (e' * w) mod n, and compute u2 = (r' * w) mod n.
472 BnModMult(bnU1, bnE, bnW, order);
473 BnModMult(bnU2, bnR, bnW, order);
474 // 6. Compute the elliptic curve point R = (xR, yR) = u1G+u2Q, using EC
475 // scalar multiplication and EC addition (see [Routines]). If R is equal to
476 // the point at infinity O, output INVALID.
477 if(BnPointMult(ecR, CurveGetG(AccessCurveData(E)), bnU1, ecQ, bnU2, E)
478 != TPM_RC_SUCCESS)
479 goto Exit;
480 // 7. Compute v = Rx mod n.
481 BnMod(ecR->x, order);
482 // 8. Compare v and r0. If v = r0, output VALID; otherwise, output INVALID
483 if(BnUnsignedCmp(ecR->x, bnR) != 0)
484 goto Exit;
485
486 retVal = TPM_RC_SUCCESS;
487 Exit:
488 return retVal;
489 }
490 #endif // ALG_ECDSA
491 #if ALG_SM2
10.2.12.3.9 BnValidateSignatureEcSm2()
10.2.12.3.10 BnValidateSignatureEcSchnorr()
10.2.12.3.11 CryptEccValidateSignature()
This function validates an EcDsa() or EcSchnorr() signature. The point Qin needs to have been validated
to be on the curve of curveId.
657 signature->signature.any.hashAlg,
658 E, ecQ, digest);
659 break;
660 #endif
661 #if ALG_SM2
662 case ALG_SM2_VALUE:
663 retVal = BnValidateSignatureEcSm2(bnR, bnS, E, ecQ, digest);
664 break;
665 #endif
666 default:
667 FAIL(FATAL_ERROR_INTERNAL);
668 }
669 Exit:
670 CURVE_FREE(E);
671 return retVal;
672 }
10.2.12.3.12 CryptEccCommitCompute()
705 {
706 ECC_INITIALIZED(bnD, d);
707 POINT_INITIALIZED(pB, B);
708 POINT(pK);
709 POINT(pL);
710 //
711 pAssert(d != NULL && K != NULL && L != NULL);
712
713 if(!BnIsOnCurve(pB, AccessCurveData(curve)))
714 ERROR_RETURN(TPM_RC_VALUE);
715 // do the math for K = [d]B
716 if((retVal = BnPointMult(pK, pB, bnD, NULL, NULL, curve)) != TPM_RC_SUCCESS)
717 goto Exit;
718 // Convert BN K to TPM2B K
719 BnPointTo2B(K, pK, curve);
720 // compute L= [r]B after checking for cancel
721 if(_plat__IsCanceled())
722 ERROR_RETURN(TPM_RC_CANCELED);
723 // compute L = [r]B
724 if(!BnIsValidPrivateEcc(bnR, curve))
725 ERROR_RETURN(TPM_RC_VALUE);
726 if((retVal = BnPointMult(pL, pB, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS)
727 goto Exit;
728 // Convert BN L to TPM2B L
729 BnPointTo2B(L, pL, curve);
730 }
731 if((M != NULL) || (B == NULL))
732 {
733 POINT_INITIALIZED(pM, M);
734 POINT(pE);
735 //
736 // Make sure that a place was provided for the result
737 pAssert(E != NULL);
738
739 // if this is the third point multiply, check for cancel first
740 if((B != NULL) && _plat__IsCanceled())
741 ERROR_RETURN(TPM_RC_CANCELED);
742
743 // If M provided, then pM will not be NULL and will compute E = [r]M.
744 // However, if M was not provided, then pM will be NULL and E = [r]G
745 // will be computed
746 if((retVal = BnPointMult(pE, pM, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS)
747 goto Exit;
748 // Convert E to 2B format
749 BnPointTo2B(E, pE, curve);
750 }
751 Exit:
752 CURVE_FREE(curve);
753 return retVal;
754 }
755 #endif // ALG_ECC
10.2.13 CryptHash.c
10.2.13.1 Description
1 #define _CRYPT_HASH_C_
2 #include "Tpm.h"
3 #include "CryptHash_fp.h"
4 #include "CryptHash.h"
5 #include "OIDs.h"
6 #define HASH_TABLE_SIZE (HASH_COUNT + 1)
7 #if ALG_SHA1
8 HASH_DEF_TEMPLATE(SHA1, Sha1);
9 #endif
10 #if ALG_SHA256
11 HASH_DEF_TEMPLATE(SHA256, Sha256);
12 #endif
13 #if ALG_SHA384
14 HASH_DEF_TEMPLATE(SHA384, Sha384);
15 #endif
16 #if ALG_SHA512
17 HASH_DEF_TEMPLATE(SHA512, Sha512);
18 #endif
19 #if ALG_SM3_256
20 HASH_DEF_TEMPLATE(SM3_256, Sm3_256);
21 #endif
22 HASH_DEF NULL_Def = {{0}};
23
24 PHASH_DEF HashDefArray[] = {
25 #if ALG_SHA1
26 &Sha1_Def,
27 #endif
28 #if ALG_SHA256
29 &Sha256_Def,
30 #endif
31 #if ALG_SHA384
32 &Sha384_Def,
33 #endif
34 #if ALG_SHA512
35 &Sha512_Def,
36 #endif
37 #if ALG_SM3_256
38 &Sm3_256_Def,
39 #endif
40 &NULL_Def
41 };
42
43 //** Obligatory Initialization Functions
44
45 //*** CryptHashInit()
46 // This function is called by _TPM_Init do perform the initialization operations for
47 // the library.
48 BOOL
49 CryptHashInit(
50 void
51 )
52 {
53 LibHashInit();
54 return TRUE;
55 }
10.2.13.2.1 CryptHashStartup()
This function is called by TPM2_Startup(). It checks that the size of the HashDefArray() is consistent with
the HASH_COUNT.
56 BOOL
57 CryptHashStartup(
58 void
59 )
60 {
61 int i = sizeof(HashDefArray) / sizeof(PHASH_DEF) - 1;
62 return (i == HASH_COUNT);
63 }
10.2.13.3.1 Introduction
10.2.13.3.2 CryptGetHashDef()
This function accesses the hash descriptor associated with a hash a algorithm. The function returns a
pointer to a null descriptor if hashAlg is TPM_ALG_NULL or not a defined algorithm.
64 PHASH_DEF
65 CryptGetHashDef(
66 TPM_ALG_ID hashAlg
67 )
68 {
69 size_t i;
70 #define HASHES (sizeof(HashDefArray) / sizeof(PHASH_DEF))
71 for(i = 0; i < HASHES; i++)
72 {
73 PHASH_DEF p = HashDefArray[i];
74 if(p->hashAlg == hashAlg)
75 return p;
76 }
77 return &NULL_Def;
78 }
10.2.13.3.3 CryptHashIsValidAlg()
This function tests to see if an algorithm ID is a valid hash algorithm. If flag is true, then TPM_ALG_NULL
is a valid hash.
79 BOOL
80 CryptHashIsValidAlg(
81 TPM_ALG_ID hashAlg, // IN: the algorithm to check
82 BOOL flag // IN: TRUE if TPM_ALG_NULL is to be treated
83 // as a valid hash
84 )
85 {
86 if(hashAlg == TPM_ALG_NULL)
87 return flag;
88 return CryptGetHashDef(hashAlg) != &NULL_Def;
89 }
10.2.13.3.4 CryptHashGetAlgByIndex()
This function is used to iterate through the hashes. TPM_ALG_NULL is returned for all indexes that are
not valid hashes. If the TPM implements 3 hashes, then an index value of 0 will return the first
implemented hash and an index of 2 will return the last. All other index values will return
TPM_ALG_NULL.
90 LIB_EXPORT TPM_ALG_ID
91 CryptHashGetAlgByIndex(
92 UINT32 index // IN: the index
93 )
94 {
95 TPM_ALG_ID hashAlg;
96 if(index >= HASH_COUNT)
97 hashAlg = TPM_ALG_NULL;
98 else
99 hashAlg = HashDefArray[index]->hashAlg;
100 return hashAlg;
101 }
10.2.13.3.5 CryptHashGetDigestSize()
Returns the size of the digest produced by the hash. If hashAlg is not a hash algorithm, the TPM will
FAIL.
10.2.13.3.6 CryptHashGetBlockSize()
Returns the size of the block used by the hash. If hashAlg is not a hash algorithm, the TPM will FAIL.
10.2.13.3.7 CryptHashGetOid()
This function returns a pointer to DER=encoded OID for a hash algorithm. All OIDs are full OID values
including the Tag (0x06) and length byte.
10.2.13.3.8 CryptHashGetContextAlg()
This function returns the hash algorithm associated with a hash context.
123 TPM_ALG_ID
124 CryptHashGetContextAlg(
125 PHASH_STATE state // IN: the context to check
126 )
127 {
128 return state->hashAlg;
129 }
10.2.13.4.1 CryptHashCopyState
10.2.13.4.2 CryptHashExportState()
This function is used to export a hash or HMAC hash state. This function would be called when preparing
to context save a sequence object.
151 void
152 CryptHashExportState(
153 PCHASH_STATE internalFmt, // IN: the hash state formatted for use by
154 // library
155 PEXPORT_HASH_STATE externalFmt // OUT: the exported hash state
156 )
157 {
158 BYTE *outBuf = (BYTE *)externalFmt;
159 //
160 cAssert(sizeof(HASH_STATE) <= sizeof(EXPORT_HASH_STATE));
161 // the following #define is used to move data from an aligned internal data
162 // structure to a byte buffer (external format data.
163 #define CopyToOffset(value) \
164 memcpy(&outBuf[offsetof(HASH_STATE,value)], &internalFmt->value, \
165 sizeof(internalFmt->value))
166 // Copy the hashAlg
167 CopyToOffset(hashAlg);
168 CopyToOffset(type);
169 #ifdef HASH_STATE_SMAC
170 if(internalFmt->type == HASH_STATE_SMAC)
171 {
172 memcpy(outBuf, internalFmt, sizeof(HASH_STATE));
173 return;
174
175 }
176 #endif
177 if(internalFmt->type == HASH_STATE_HMAC)
178 {
179 HMAC_STATE *from = (HMAC_STATE *)internalFmt;
180 memcpy(&outBuf[offsetof(HMAC_STATE, hmacKey)], &from->hmacKey,
181 sizeof(from->hmacKey));
182 }
183 if(internalFmt->hashAlg != TPM_ALG_NULL)
184 HASH_STATE_EXPORT(externalFmt, internalFmt);
185 }
10.2.13.4.3 CryptHashImportState()
This function is used to import the hash state. This function would be called to import a hash state when
the context of a sequence object was being loaded.
186 void
187 CryptHashImportState(
188 PHASH_STATE internalFmt, // OUT: the hash state formatted for use by
189 // the library
190 PCEXPORT_HASH_STATE externalFmt // IN: the exported hash state
191 )
192 {
193 BYTE *inBuf = (BYTE *)externalFmt;
194 //
10.2.13.5.1 HashEnd()
Local function to complete a hash that uses the hashDef instead of an algorithm ID. This function is used
to complete the hash and only return a partial digest. The return value is the size of the data copied.
10.2.13.5.2 CryptHashStart()
Functions starts a hash stack Start a hash stack and returns the digest size. As a side effect, the value of
stateSize in hashState is updated to indicate the number of bytes of state that were saved. This function
calls GetHashServer() and that function will put the TPM into failure mode if the hash algorithm is not
supported.
This function does not use the sequence parameter. If it is necessary to import or export context, this will
start the sequence in a local state and export the state to the input buffer. Will need to add a flag to the
state structure to indicate that it needs to be imported before it can be used. (BLEH).
10.2.13.5.3 CryptDigestUpdate()
273 void
274 CryptDigestUpdate(
275 PHASH_STATE hashState, // IN: the hash context information
276 UINT32 dataSize, // IN: the size of data to be added
277 const BYTE *data // IN: data to be hashed
278 )
279 {
280 if(hashState->hashAlg != TPM_ALG_NULL)
281 {
282 if((hashState->type == HASH_STATE_HASH)
283 || (hashState->type == HASH_STATE_HMAC))
284 HASH_DATA(hashState, dataSize, (BYTE *)data);
285 #if SMAC_IMPLEMENTED
286 else if(hashState->type == HASH_STATE_SMAC)
287 (hashState->state.smac.smacMethods.data)(&hashState->state.smac.state,
288 dataSize, data);
10.2.13.5.4 CryptHashEnd()
Complete a hash or HMAC computation. This function will place the smaller of digestSize or the size of
the digest in dOut. The number of bytes in the placed in the buffer is returned. If there is a failure, the
returned value is <= 0.
10.2.13.5.5 CryptHashBlock()
Start a hash, hash a single block, update digest and return the size of the results.
The digestSize parameter can be smaller than the digest. If so, only the more significant bytes are
returned.
10.2.13.5.6 CryptDigestUpdate2B()
This function can be used for both HMAC and hash functions so the digestState is void so that either
state type can be passed.
10.2.13.5.7 CryptHashEnd2B()
This function is the same as CryptCompleteHash() but the digest is placed in a TPM2B. This is the most
common use and this is provided for specification clarity. digest.size should be set to indicate the number
of bytes to place in the buffer
10.2.13.5.8 CryptDigestUpdateInt()
This function is used to include an integer value to a hash stack. The function marshals the integer into its
canonical form before calling CryptDigestUpdate().
10.2.13.6.1 CryptHmacStart()
This function is used to start an HMAC using a temp hash context. The function does the initialization of
the hash with the HMAC key XOR iPad and updates the HMAC key XOR oPad.
The function returns the number of bytes in a digest produced by hashAlg.
10.2.13.6.2 CryptHmacEnd()
This function is called to complete an HMAC. It will finish the current digest, and start a new digest. It will
then add the oPadKey and the completed digest and return the results in dOut. It will not return more than
dOutSize bytes.
10.2.13.6.3 CryptHmacStart2B()
This function starts an HMAC and returns the size of the digest that will be produced.
This function is provided to support the most common use of starting an HMAC with a TPM2B key.
The caller must provide a block of memory in which the hash sequence state is kept. The caller should
not alter the contents of this buffer until the hash sequence is completed or abandoned.
10.2.13.6.4 CryptHmacEnd2B()
This function is the same as CryptHmacEnd() but the HMAC result is returned in a TPM2B which is the
most common use.
10.2.13.7.1 CryptMGF1()
This function performs MGF1 using the selected hash. MGF1 is T(n) = T(n-1) || H(seed || counter). This
function returns the length of the mask produced which could be zero if the digest algorithm is not
supported
10.2.13.7.2 CryptKDFa()
This function performs the key generation according to Part 1 of the TPM specification.
This function returns the number of bytes generated which may be zero.
The key and keyStream pointers are not allowed to be NULL. The other pointer values may be NULL.
The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes).
The once parameter is set to allow incremental generation of a large value. If this flag is TRUE, sizeInBits
will be used in the HMAC computation but only one iteration of the KDF is performed. This would be used
for XOR obfuscation so that the mask value can be generated in digest-sized chunks rather than having
to be generated all at once in an arbitrarily large buffer and then XORed into the result. If once is TRUE,
then sizeInBits must be a multiple of 8.
Any error in the processing of this command is considered fatal.
10.2.13.7.3 CryptKDFe()
10.2.14 CryptPrime.c
10.2.14.1 Introduction
1 #include "Tpm.h"
2 #include "CryptPrime_fp.h"
3 //#define CPRI_PRIME
4 //#include "PrimeTable.h"
5 #include "CryptPrimeSieve_fp.h"
6 extern const uint32_t s_LastPrimeInTable;
7 extern const uint32_t s_PrimeTableSize;
8 extern const uint32_t s_PrimesInTable;
9 extern const unsigned char s_PrimeTable[];
10 extern bigConst s_CompositeOfSmallPrimes;
11
12 //** Functions
13
14 //*** Root2()
15 // This finds ceil(sqrt(n)) to use as a stopping point for searching the prime
16 // table.
17 static uint32_t
18 Root2(
19 uint32_t n
20 )
21 {
22 int32_t last = (int32_t)(n >> 2);
23 int32_t next = (int32_t)(n >> 1);
24 int32_t diff;
25 int32_t stop = 10;
26 //
27 // get a starting point
28 for(; next != 0; last >>= 1, next >>= 2);
29 last++;
30 do
31 {
32 next = (last + (n / last)) >> 1;
33 diff = next - last;
34 last = next;
35 if(stop-- == 0)
36 FAIL(FATAL_ERROR_INTERNAL);
37 } while(diff < -1 || diff > 1);
38 if((n / next) > (unsigned)next)
39 next++;
40 pAssert(next != 0);
41 pAssert(((n / next) <= (unsigned)next) && (n / (next + 1) < (unsigned)next));
42 return next;
43 }
10.2.14.1.1 IsPrimeInt()
44 BOOL
45 IsPrimeInt(
46 uint32_t n
47 )
48 {
49 uint32_t i;
50 uint32_t stop;
51 if(n < 3 || ((n & 1) == 0))
52 return (n == 2);
53 if(n <= s_LastPrimeInTable)
54 {
55 n >>= 1;
56 return ((s_PrimeTable[n >> 3] >> (n & 7)) & 1);
57 }
58 // Need to search
59 stop = Root2(n) >> 1;
60 // starting at 1 is equivalent to staring at (1 << 1) + 1 = 3
61 for(i = 1; i < stop; i++)
62 {
63 if((s_PrimeTable[i >> 3] >> (i & 7)) & 1)
64 // see if this prime evenly divides the number
65 if((n % ((i << 1) + 1)) == 0)
66 return FALSE;
67 }
68 return TRUE;
69 }
10.2.14.1.2 BnIsProbablyPrime()
This function is used when the key sieve is not implemented. This function Will try to eliminate some of
the obvious things before going on to perform MillerRabin() as a final verification of primeness.
70 BOOL
71 BnIsProbablyPrime(
72 bigNum prime, // IN:
73 RAND_STATE *rand // IN: the random state just
74 // in case Miller-Rabin is required
75 )
76 {
77 #if RADIX_BITS > 32
78 if(BnUnsignedCmpWord(prime, UINT32_MAX) <= 0)
79 #else
80 if(BnGetSize(prime) == 1)
81 #endif
82 return IsPrimeInt((uint32_t)prime->d[0]);
83
84 if(BnIsEven(prime))
85 return FALSE;
86 if(BnUnsignedCmpWord(prime, s_LastPrimeInTable) <= 0)
87 {
88 crypt_uword_t temp = prime->d[0] >> 1;
89 return ((s_PrimeTable[temp >> 3] >> (temp & 7)) & 1);
90 }
91 {
92 BN_VAR(n, LARGEST_NUMBER_BITS);
93 BnGcd(n, prime, s_CompositeOfSmallPrimes);
94 if(!BnEqualWord(n, 1))
95 return FALSE;
96 }
97 return MillerRabin(prime, rand);
98 }
10.2.14.1.3 MillerRabinRounds()
Function returns the number of Miller-Rabin rounds necessary to give an error probability equal to the
security strength of the prime. These values are from FIPS 186-3.
99 UINT32
100 MillerRabinRounds(
101 UINT32 bits // IN: Number of bits in the RSA prime
102 )
103 {
104 if(bits < 511) return 8; // don't really expect this
105 if(bits < 1536) return 5; // for 512 and 1K primes
106 return 4; // for 3K public modulus and greater
107 }
10.2.14.1.4 MillerRabin()
This function performs a Miller-Rabin test from FIPS 186-3. It does iterations trials on the number. In all
likelihood, if the number is not prime, the first test fails.
108 BOOL
109 MillerRabin(
110 bigNum bnW,
111 RAND_STATE *rand
112 )
113 {
114 BN_MAX(bnWm1);
115 BN_PRIME(bnM);
116 BN_PRIME(bnB);
117 BN_PRIME(bnZ);
118 BOOL ret = FALSE; // Assumed composite for easy exit
119 unsigned int a;
120 unsigned int j;
121 int wLen;
122 int i;
123 int iterations = MillerRabinRounds(BnSizeInBits(bnW));
124 //
125 INSTRUMENT_INC(MillerRabinTrials[PrimeIndex]);
126
127 pAssert(bnW->size > 1);
128 // Let a be the largest integer such that 2^a divides w1.
129 BnSubWord(bnWm1, bnW, 1);
130 pAssert(bnWm1->size != 0);
131
132 // Since w is odd (w-1) is even so start at bit number 1 rather than 0
133 // Get the number of bits in bnWm1 so that it doesn't have to be recomputed
134 // on each iteration.
135 i = (int)(bnWm1->size * RADIX_BITS);
136 // Now find the largest power of 2 that divides w1
137 for(a = 1;
138 (a < (bnWm1->size * RADIX_BITS)) &&
139 (BnTestBit(bnWm1, a) == 0);
140 a++);
141 // 2. m = (w1) / 2^a
142 BnShiftRight(bnM, bnWm1, a);
143 // 3. wlen = len (w).
144 wLen = BnSizeInBits(bnW);
145 // 4. For i = 1 to iterations do
146 for(i = 0; i < iterations; i++)
147 {
148 // 4.1 Obtain a string b of wlen bits from an RBG.
149 // Ensure that 1 < b < w1.
150 // 4.2 If ((b <= 1) or (b >= w1)), then go to step 4.1.
151 while(BnGetRandomBits(bnB, wLen, rand) && ((BnUnsignedCmpWord(bnB, 1) <= 0)
152 || (BnUnsignedCmp(bnB, bnWm1) >= 0)));
153 if(g_inFailureMode)
10.2.14.1.5 RsaCheckPrime()
This will check to see if a number is prime and appropriate for an RSA prime.
This has different functionality based on whether we are using key sieving or not. If not, the number
checked to see if it is divisible by the public exponent, then the number is adjusted either up or down in
order to make it a better candidate. It is then checked for being probably prime.
If sieving is used, the number is used to root a sieving process.
191 TPM_RC
192 RsaCheckPrime(
193 bigNum prime,
194 UINT32 exponent,
195 RAND_STATE *rand
196 )
197 {
198 #if !RSA_KEY_SIEVE
199 TPM_RC retVal = TPM_RC_SUCCESS;
200 UINT32 modE = BnModWord(prime, exponent);
201
202 NOT_REFERENCED(rand);
203
204 if(modE == 0)
205 // evenly divisible so add two keeping the number odd
206 BnAddWord(prime, prime, 2);
10.2.14.1.6 AdjustPrimeCandiate()
For this math, we assume that the RSA numbers are fixed-point numbers with the decimal point to the left
of the most significant bit. This approach helps make it clear what is happening with the MSb of the
values. The two RSA primes have to be large enough so that their product will be a number with the
necessary number of significant bits. For example, we want to be able to multiply two 1024-bit numbers to
produce a number with 2048 significant bits. If we accept any 1024-bit prime that has its MSb set, then it
is possible to produce a product that does not have the MSb SET. For example, if we use tiny keys of 16
bits and have two 8-bit primes of 0x80, then the public key would be 0x4000 which is only 15-bits. So,
what we need to do is made sure that each of the primes is large enough so that the product of the
primes is twice as large as each prime. A little arithmetic will show that the only way to do this is to make
sure that each of the primes is no less than root(2)/2. That's what this functions does. This function
adjusts the candidate prime so that it is odd and >= root(2)/2. This allows the product of these two
numbers to be .5, which, in fixed point notation means that the most significant bit is 1. For this routine,
the root(2)/2 (0.7071067811865475) approximated with 0xB505 which is, in fixed point,
0.7071075439453125 or an error of 0.000108%. Just setting the upper two bits would give a value > 0.75
which is an error of > 6%. Given the amount of time all the other computations take, reducing the error is
not much of a cost, but it isn't totally required either.
This function can be replaced with a function that just sets the two most significant bits of each prime
candidate without introducing any computational issues.
246 }
10.2.14.1.7 BnGeneratePrimeForRSA()
Function to generate a prime of the desired size with the proper attributes for an RSA prime.
247 TPM_RC
248 BnGeneratePrimeForRSA(
249 bigNum prime, // IN/OUT: points to the BN that will get the
250 // random value
251 UINT32 bits, // IN: number of bits to get
252 UINT32 exponent, // IN: the exponent
253 RAND_STATE *rand // IN: the random state
254 )
255 {
256 BOOL found = FALSE;
257 //
258 // Make sure that the prime is large enough
259 pAssert(prime->allocated >= BITS_TO_CRYPT_WORDS(bits));
260 // Only try to handle specific sizes of keys in order to save overhead
261 pAssert((bits % 32) == 0);
262
263 prime->size = BITS_TO_CRYPT_WORDS(bits);
264
265 while(!found)
266 {
267 // The change below is to make sure that all keys that are generated from the same
268 // seed value will be the same regardless of the endianess or word size of the CPU.
269 // DRBG_Generate(rand, (BYTE *)prime->d, (UINT16)BITS_TO_BYTES(bits));// old
270 // if(g_inFailureMode) // old
271 if(!BnGetRandomBits(prime, bits, rand)) // new
272 return TPM_RC_FAILURE;
273 RsaAdjustPrimeCandidate(prime);
274 found = RsaCheckPrime(prime, exponent, rand) == TPM_RC_SUCCESS;
275 }
276 return TPM_RC_SUCCESS;
277 }
278 #endif // ALG_RSA
10.2.15 CryptPrimeSieve.c
1 #include "Tpm.h"
2 #if RSA_KEY_SIEVE
3 #include "CryptPrimeSieve_fp.h"
10.2.15.1.1 RsaNextPrime()
This the iterator used during the sieve process. The input is the last prime returned (or any starting point)
and the output is the next higher prime. The function returns 0 when the primeLimit is reached.
46 LIB_EXPORT uint32_t
47 RsaNextPrime(
48 uint32_t lastPrime
49 )
50 {
51 if(lastPrime == 0)
52 return 0;
53 lastPrime >>= 1;
54 for(lastPrime += 1; lastPrime <= primeLimit; lastPrime++)
55 {
56 if(((s_PrimeTable[lastPrime >> 3] >> (lastPrime & 0x7)) & 1) == 1)
57 return ((lastPrime << 1) + 1);
58 }
59 return 0;
60 }
This table contains a previously sieved table. It has the bits for 3, 5, and 7 removed. Because of the
factors, it needs to be aligned to 105 and has a repeat of 105.
10.2.15.1.2 BitsInArry()
10.2.15.1.3 FindNthSetBit()
This function finds the nth SET bit in a bit array. The n parameter is between 1 and the number of bits in
the array (always a multiple of 8). If called when the array does not have n bits set, it will return -1
10.2.15.1.4 PrimeSelectWithSieve()
This function will sieve the field around the input prime candidate. If the sieve field is not empty, one of
the one bits in the field is chosen for testing with Miller-Rabin. If the value is prime, pnP is updated with
this value and the function returns success. If this value is not prime, another pseudo-random candidate
is chosen and tested. This process repeats until all values in the field have been checked. If all bits in the
field have been checked and none is prime, the function returns FALSE and a new random value needs
to be chosen.
397
398 //*** PrintTuple()
399 char *
400 PrintTuple(
401 UINT32 *i
402 )
403 {
404 sprintf(a, "{%d, %d, %d}", i[0], i[1], i[2]);
405 return a;
406 }
407
408 #define CLEAR_VALUE(x) memset(x, 0, sizeof(x))
409
410 //*** RsaSimulationEnd()
411 void
412 RsaSimulationEnd(
413 void
414 )
415 {
416 int i;
417 UINT32 averages[3];
418 UINT32 nonFirst = 0;
419 if((PrimeCounts[0] + PrimeCounts[1] + PrimeCounts[2]) != 0)
420 {
421 printf("Primes generated = %s\n", PrintTuple(PrimeCounts));
422 printf("Fields sieved = %s\n", PrintTuple(totalFieldsSieved));
423 printf("Fields with no primes = %s\n", PrintTuple(noPrimeFields));
424 printf("Primes checked with Miller-Rabin = %s\n",
425 PrintTuple(MillerRabinTrials));
426 for(i = 0; i < 3; i++)
427 averages[i] = (totalFieldsSieved[i]
428 != 0 ? bitsInFieldAfterSieve[i] / totalFieldsSieved[i]
429 : 0);
430 printf("Average candidates in field %s\n", PrintTuple(averages));
431 for(i = 1; i < (sizeof(failedAtIteration) / sizeof(failedAtIteration[0]));
432 i++)
433 nonFirst += failedAtIteration[i];
434 printf("Miller-Rabin failures not in first round = %d\n", nonFirst);
435
436 }
437 CLEAR_VALUE(PrimeCounts);
438 CLEAR_VALUE(totalFieldsSieved);
439 CLEAR_VALUE(noPrimeFields);
440 CLEAR_VALUE(MillerRabinTrials);
441 CLEAR_VALUE(bitsInFieldAfterSieve);
442 }
443
444 //*** GetSieveStats()
445 LIB_EXPORT void
446 GetSieveStats(
447 uint32_t *trials,
448 uint32_t *emptyFields,
449 uint32_t *averageBits
450 )
451 {
452 uint32_t totalBits;
453 uint32_t fields;
454 *trials = MillerRabinTrials[0] + MillerRabinTrials[1] + MillerRabinTrials[2];
455 *emptyFields = noPrimeFields[0] + noPrimeFields[1] + noPrimeFields[2];
456 fields = totalFieldsSieved[0] + totalFieldsSieved[1]
457 + totalFieldsSieved[2];
458 totalBits = bitsInFieldAfterSieve[0] + bitsInFieldAfterSieve[1]
459 + bitsInFieldAfterSieve[2];
460 if(fields != 0)
461 *averageBits = totalBits / fields;
462 else
463 *averageBits = 0;
464 CLEAR_VALUE(PrimeCounts);
465 CLEAR_VALUE(totalFieldsSieved);
466 CLEAR_VALUE(noPrimeFields);
467 CLEAR_VALUE(MillerRabinTrials);
468 CLEAR_VALUE(bitsInFieldAfterSieve);
469
470 }
471 #endif
472
473 #endif // RSA_KEY_SIEVE
474
475 #if !RSA_INSTRUMENT
476
477 //*** RsaSimulationEnd()
478 // Stub for call when not doing instrumentation.
479 void
480 RsaSimulationEnd(
481 void
482 )
483 {
484 return;
485 }
486 #endif
10.2.16 CryptRand.c
10.2.16.1 Introduction
This file implements a DRBG with a behavior according to SP800-90A using a block cypher. This is also
compliant to ISO/IEC 18031:2011(E) C.3.2.
A state structure is created for use by TPM.lib and functions within the CryptoEngine() my use their own
state structures when they need to have deterministic values.
A debug mode is available that allows the random numbers generated for TPM.lib to be repeated during
runs of the simulator. The switch for it is in TpmBuildSwitches.h. It is USE_DEBUG_RNG.
This is the implementation layer of CTR DRGB mechanism as defined in SP800-90A and the functions
are organized as closely as practical to the organization in SP800-90A. It is intended to be compiled as a
separate module that is linked with a secure application so that both reside inside the same boundary [SP
800-90A 8.5]. The secure application in particular manages the accesses protected storage for the state
of the DRBG instantiations, and supplies the implementation functions here with a valid pointer to the
working state of the given instantiations (as a DRBG_STATE structure).
This DRBG mechanism implementation does not support prediction resistance. Thus
prediction_resistance_flag is omitted from Instantiate_function(), Reseed_function(), Generate_function()
argument lists [SP 800-90A 9.1, 9.2, 9.3], as well as from the working state data structure DRBG_STATE
[SP 800-90A 9.1].
This DRBG mechanism implementation always uses the highest security strength of available in the block
ciphers. Thus requested_security_strength parameter is omitted from Instantiate_function() and
Generate_function() argument lists [SP 800-90A 9.1, 9.2, 9.3], as well as from the working state data
structure DRBG_STATE [SP 800-90A 9.1].
Internal functions (ones without Crypt prefix) expect validated arguments and therefore use assertions
instead of runtime parameter checks and mostly return void instead of a status value.
1 #include "Tpm.h"
2 #include "PRNG_TestVectors.h"
3 const BYTE DRBG_NistTestVector_Entropy[] = {DRBG_TEST_INITIATE_ENTROPY};
4 const BYTE DRBG_NistTestVector_GeneratedInterm[] =
5 {DRBG_TEST_GENERATED_INTERM};
6
7 const BYTE DRBG_NistTestVector_EntropyReseed[] =
8 {DRBG_TEST_RESEED_ENTROPY};
9 const BYTE DRBG_NistTestVector_Generated[] = {DRBG_TEST_GENERATED};
10
11 //** Derivation Functions
12 //*** Description
13 // The functions in this section are used to reduce the personalization input values
14 // to make them usable as input for reseeding and instantiation. The overall
15 // behavior is intended to produce the same results as described in SP800-90A,
16 // section 10.4.2 "Derivation Function Using a Block Cipher Algorithm
17 // (Block_Cipher_df)." The code is broken into several subroutines to deal with the
18 // fact that the data used for personalization may come in several separate blocks
19 // such as a Template hash and a proof value and a primary seed.
20
21 //*** Derivation Function Defines and Structures
22
23 #define DF_COUNT (DRBG_KEY_SIZE_WORDS / DRBG_IV_SIZE_WORDS + 1)
24 #if DRBG_KEY_SIZE_BITS != 128 && DRBG_KEY_SIZE_BITS != 256
25 # error "CryptRand.c only written for AES with 128- or 256-bit keys."
26 #endif
27 typedef struct
28 {
29 DRBG_KEY_SCHEDULE keySchedule;
30 DRBG_IV iv[DF_COUNT];
31 DRBG_IV out1;
32 DRBG_IV buf;
33 int contents;
34 } DF_STATE, *PDF_STATE;
10.2.16.1.1 DfCompute()
This function does the incremental update of the derivation function state. It encrypts the iv value and
XOR's the results into each of the blocks of the output. This is equivalent to processing all of input data
for each output block.
35 static void
36 DfCompute(
37 PDF_STATE dfState
38 )
39 {
40 int i;
41 int iv;
42 crypt_uword_t *pIv;
43 crypt_uword_t temp[DRBG_IV_SIZE_WORDS] = {0};
44 //
45 for(iv = 0; iv < DF_COUNT; iv++)
46 {
47 pIv = (crypt_uword_t *)&dfState->iv[iv].words[0];
48 for(i = 0; i < DRBG_IV_SIZE_WORDS; i++)
49 {
50 temp[i] ^= pIv[i] ^ dfState->buf.words[i];
51 }
52 DRBG_ENCRYPT(&dfState->keySchedule, &temp, pIv);
53 }
54 for(i = 0; i < DRBG_IV_SIZE_WORDS; i++)
55 dfState->buf.words[i] = 0;
56 dfState->contents = 0;
57 }
10.2.16.1.2 DfStart()
This initializes the output blocks with an encrypted counter value and initializes the key schedule.
58 static void
59 DfStart(
60 PDF_STATE dfState,
61 uint32_t inputLength
62 )
63 {
64 BYTE init[8];
65 int i;
66 UINT32 drbgSeedSize = sizeof(DRBG_SEED);
67
68 const BYTE dfKey[DRBG_KEY_SIZE_BYTES] = {
69 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
70 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
71 #if DRBG_KEY_SIZE_BYTES > 16
72 ,0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
73 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
74 #endif
75 };
76 memset(dfState, 0, sizeof(DF_STATE));
10.2.16.1.3 DfUpdate()
This updates the state with the input data. A byte at a time is moved into the state buffer until it is full and
then that block is encrypted by DfCompute().
89 static void
90 DfUpdate(
91 PDF_STATE dfState,
92 int size,
93 const BYTE *data
94 )
95 {
96 while(size > 0)
97 {
98 int toFill = DRBG_IV_SIZE_BYTES - dfState->contents;
99 if(size < toFill)
100 toFill = size;
101 // Copy as many bytes as there are or until the state buffer is full
102 memcpy(&dfState->buf.bytes[dfState->contents], data, toFill);
103 // Reduce the size left by the amount copied
104 size -= toFill;
105 // Advance the data pointer by the amount copied
106 data += toFill;
107 // increase the buffer contents count by the amount copied
108 dfState->contents += toFill;
109 pAssert(dfState->contents <= DRBG_IV_SIZE_BYTES);
110 // If we have a full buffer, do a computation pass.
111 if(dfState->contents == DRBG_IV_SIZE_BYTES)
112 DfCompute(dfState);
113 }
114 }
10.2.16.1.4 DfEnd()
This function is called to get the result of the derivation function computation. If the buffer is not full, it is
padded with zeros. The output buffer is structured to be the same as a DRBG_SEED value so that the
function can return a pointer to the DRBG_SEED value in the DF_STATE structure.
10.2.16.1.5 DfBuffer()
Function to take an input buffer and do the derivation function to produce a DRBG_SEED value that can
be used in DRBG_Reseed();
10.2.16.1.6 DRBG_GetEntropy()
Even though this implementation never fails, it may get blocked indefinitely long in the call to get entropy
from the platform (DRBG_GetEntropy32()). This function is only used during instantiation of the DRBG for
manufacturing and on each start-up after an non-orderly shutdown.
147 BOOL
148 DRBG_GetEntropy(
149 UINT32 requiredEntropy, // IN: requested number of bytes of full
150 // entropy
151 BYTE *entropy // OUT: buffer to return collected entropy
152 )
153 {
154 #if !USE_DEBUG_RNG
155
156 UINT32 obtainedEntropy;
157 INT32 returnedEntropy;
158
159 // If in debug mode, always use the self-test values for initialization
160 if(IsSelfTest())
161 {
162 #endif
163 // If doing simulated DRBG, then check to see if the
164 // entropyFailure condition is being tested
165 if(!IsEntropyBad())
166 {
167 // In self-test, the caller should be asking for exactly the seed
168 // size of entropy.
10.2.16.1.7 IncrementIv()
193 void
194 IncrementIv(
195 DRBG_IV *iv
196 )
197 {
198 BYTE *ivP = ((BYTE *)iv) + DRBG_IV_SIZE_BYTES;
199 while((--ivP >= (BYTE *)iv) && ((*ivP = ((*ivP + 1) & 0xFF)) == 0));
200 }
10.2.16.1.8 EncryptDRBG()
This does the encryption operation for the DRBG. It will encrypt the input state counter (IV) using the
state key. Into the output buffer for as many times as it takes to generate the required number of bytes.
221 // Increment the IV before each encryption (this is what makes this
222 // different from normal counter-mode encryption
223 IncrementIv(iv);
224 DRBG_ENCRYPT(keySchedule, iv, temp);
225 // Expect a 16 byte block
226 #if DRBG_IV_SIZE_BITS != 128
227 #error "Unsuppored IV size in DRBG"
228 #endif
229 if((lastValue[0] == temp[0])
230 && (lastValue[1] == temp[1])
231 && (lastValue[2] == temp[2])
232 && (lastValue[3] == temp[3])
233 )
234 {
235 LOG_FAILURE(FATAL_ERROR_ENTROPY);
236 return FALSE;
237 }
238 lastValue[0] = temp[0];
239 lastValue[1] = temp[1];
240 lastValue[2] = temp[2];
241 lastValue[3] = temp[3];
242 i = MIN(dOutBytes, DRBG_IV_SIZE_BYTES);
243 dOutBytes -= i;
244 for(p = (BYTE *)temp; i > 0; i--)
245 *dOut++ = *p++;
246 }
247 #else // version without continuous self-test
248 NOT_REFERENCED(lastValue);
249 for(; dOutBytes >= DRBG_IV_SIZE_BYTES;
250 dOut = &dOut[DRBG_IV_SIZE_BYTES], dOutBytes -= DRBG_IV_SIZE_BYTES)
251 {
252 // Increment the IV
253 IncrementIv(iv);
254 DRBG_ENCRYPT(keySchedule, iv, dOut);
255 }
256 // If there is a partial, generate into a block-sized
257 // temp buffer and copy to the output.
258 if(dOutBytes != 0)
259 {
260 BYTE temp[DRBG_IV_SIZE_BYTES];
261 // Increment the IV
262 IncrementIv(iv);
263 DRBG_ENCRYPT(keySchedule, iv, temp);
264 memcpy(dOut, temp, dOutBytes);
265 }
266 #endif
267 return TRUE;
268 }
10.2.16.1.9 DRBG_Update()
This function performs the state update function. According to SP800-90A, a temp value is created by
doing CTR mode encryption of providedData and replacing the key and IV with these values. The one
difference is that, with counter mode, the IV is incremented after each block is encrypted and in this
operation, the counter is incremented before each block is encrypted. This function implements an
optimized version of the algorithm in that it does the update of the drbgState->seed in place and then
providedData is XORed into drbgState->seed to complete the encryption of providedData. This works
because the IV is the last thing that gets encrypted.
10.2.16.1.10 DRBG_Reseed()
This function is used when reseeding of the DRBG is required. If entropy is provided, it is used in lieu of
using hardware entropy.
309 BOOL
310 DRBG_Reseed(
311 DRBG_STATE *drbgState, // IN: the state to update
312 DRBG_SEED *providedEntropy, // IN: entropy
313 DRBG_SEED *additionalData // IN:
314 )
315 {
316 DRBG_SEED seed;
317
318 pAssert((drbgState != NULL) && (drbgState->magic == DRBG_MAGIC));
319
320 if(providedEntropy == NULL)
321 {
322 providedEntropy = &seed;
10.2.16.1.11 DRBG_SelfTest()
340 BOOL
341 DRBG_SelfTest(
342 void
343 )
344 {
345 BYTE buf[sizeof(DRBG_NistTestVector_Generated)];
346 DRBG_SEED seed;
347 UINT32 i;
348 BYTE *p;
349 DRBG_STATE testState;
350 //
351 pAssert(!IsSelfTest());
352
353 SetSelfTest();
354 SetDrbgTested();
355 // Do an instantiate
356 if(!DRBG_Instantiate(&testState, 0, NULL))
357 return FALSE;
358 #if DRBG_DEBUG_PRINT
359 dbgDumpMemBlock(pDRBG_KEY(&testState), DRBG_KEY_SIZE_BYTES,
360 "Key after Instantiate");
361 dbgDumpMemBlock(pDRBG_IV(&testState), DRBG_IV_SIZE_BYTES,
362 "Value after Instantiate");
363 #endif
364 if(DRBG_Generate((RAND_STATE *)&testState, buf, sizeof(buf)) == 0)
365 return FALSE;
366 #if DRBG_DEBUG_PRINT
367 dbgDumpMemBlock(pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES,
368 "Key after 1st Generate");
369 dbgDumpMemBlock(pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES,
370 "Value after 1st Generate");
371 #endif
372 if(memcmp(buf, DRBG_NistTestVector_GeneratedInterm, sizeof(buf)) != 0)
373 return FALSE;
374 memcpy(seed.bytes, DRBG_NistTestVector_EntropyReseed, sizeof(seed));
375 DRBG_Reseed(&testState, &seed, NULL);
10.2.16.2.1 Description
The functions in this section are the interface to the RNG. These are the functions that are used by
TPM.lib.
10.2.16.2.2 CryptRandomStir()
This function is used to cause a reseed. A DRBG_SEED amount of entropy is collected from the
hardware and then additional data is added.
421
422 return TPM_RC_SUCCESS;
423
424 #else
425 // If doing debug, use the input data as the initial setting for the RNG state
426 // so that the test can be reset at any time.
427 // Note: If this is called with a data size of 0 or less, nothing happens. The
428 // presumption is that, in a debug environment, the caller will have specific
429 // values for initialization, so this check is just a simple way to prevent
430 // inadvertent programming errors from screwing things up. This doesn't use an
431 // pAssert() because the non-debug version of this function will accept these
432 // parameters as meaning that there is no additionalData and only hardware
433 // entropy is used.
434 if((additionalDataSize > 0) && (additionalData != NULL))
435 {
436 memset(drbgDefault.seed.bytes, 0, sizeof(drbgDefault.seed.bytes));
437 memcpy(drbgDefault.seed.bytes, additionalData,
438 MIN(additionalDataSize, sizeof(drbgDefault.seed.bytes)));
439 }
440 drbgDefault.reseedCounter = 1;
441
442 return TPM_RC_SUCCESS;
443 #endif
444 }
10.2.16.2.3 CryptRandomGenerate()
10.2.16.2.4 DRBG_InstantiateSeededKdf()
This function is used to instantiate a KDF-based RNG. This is used for derivations. This function always
returns TRUE.
473 state->residual.t.size = 0;
474 return TRUE;
475 }
10.2.16.2.5 DRBG_AdditionalData()
Function to reseed the DRBG with additional entropy. This is normally called before computing the
protection value of a primary key in the Endorsement hierarchy.
10.2.16.2.6 DRBG_InstantiateSeeded()
This function is used to instantiate a random number generator from seed values. The nominal use of this
generator is to create sequences of pseudo-random numbers from a seed value.
519 // Run all the input strings through the derivation function
520 if(seed != NULL)
521 DfUpdate(&dfState, seed->size, seed->buffer);
522 if(purpose != NULL)
523 DfUpdate(&dfState, purpose->size, purpose->buffer);
524 if(name != NULL)
525 DfUpdate(&dfState, name->size, name->buffer);
526 if(additional != NULL)
527 DfUpdate(&dfState, additional->size, additional->buffer);
528
529 // Used the derivation function output as the "entropy" input. This is not
530 // how it is described in SP800-90A but this is the equivalent function
531 DRBG_Reseed(((DRBG_STATE *)drbgState), DfEnd(&dfState), NULL);
532
533 return TPM_RC_SUCCESS;
534 }
10.2.16.2.7 CryptRandStartup()
This function is called when TPM_Startup is executed. This function always returns TRUE.
10.2.16.2.7.1 CryptRandInit()
10.2.16.2.8 DRBG_Generate()
This function generates a random sequence according SP800-90A. If random is not NULL, then
randomSize bytes of random values are generated. If random is NULL or randomSize is zero, then the
function returns zero without generating any bits or updating the reseed counter. This function returns the
number of bytes produced which could be less than the number requested if the request is too large ("too
large" is implementation dependent.)
596 // Don't use more of the residual than will fit or more than are
597 // available
598 size = MIN(kdf->residual.t.size, bytesLeft);
599
600 // Copy some or all of the residual to the output. The residual is
601 // at the end of the buffer. The residual might be a full buffer.
602 MemoryCopy(random,
603 &kdf->residual.t.buffer
604 [kdf->digestSize - kdf->residual.t.size], size);
605
606 // Advance the buffer pointer
607 random += size;
608
609 // Reduce the number of bytes left to get
610 bytesLeft -= size;
611
612 // And reduce the residual size appropriately
613 kdf->residual.t.size -= (UINT16)size;
614 }
615 else
616 {
617 UINT16 blocks = (UINT16)(bytesLeft / kdf->digestSize);
618 //
619 // Get the number of required full blocks
620 if(blocks > 0)
621 {
622 UINT16 size = blocks * kdf->digestSize;
623 // Get some number of full blocks and put them in the return buffer
624 CryptKDFa(kdf->hash, kdf->seed, kdf->label, kdf->context, NULL,
625 kdf->limit, random, &counter, blocks);
626
627 // reduce the size remaining to be moved and advance the pointer
628 bytesLeft -= size;
629 random += size;
630 }
631 else
632 {
633 // Fill the residual buffer with a full block and then loop to
634 // top to get part of it copied to the output.
635 kdf->residual.t.size = CryptKDFa(kdf->hash, kdf->seed,
636 kdf->label, kdf->context, NULL,
637 kdf->limit,
638 kdf->residual.t.buffer,
639 &counter, 1);
640 }
641 }
642 }
643 kdf->counter = counter;
644 return randomSize;
645 }
646 else if(state->drbg.magic == DRBG_MAGIC)
647 {
648 DRBG_STATE *drbgState = (DRBG_STATE *)state;
649 DRBG_KEY_SCHEDULE keySchedule;
650 DRBG_SEED *seed = &drbgState->seed;
651
652 if(drbgState->reseedCounter >= CTR_DRBG_MAX_REQUESTS_PER_RESEED)
653 {
654 if(drbgState == &drbgDefault)
655 {
656 DRBG_Reseed(drbgState, NULL, NULL);
657 if(IsEntropyBad() && !IsSelfTest())
658 return 0;
659 }
660 else
661 {
10.2.16.2.9 DRBG_Instantiate()
This is CTR_DRBG_Instantiate_algorithm() from [SP 800-90A 10.2.1.3.1]. This is called when a the TPM
DRBG is to be instantiated. This is called to instantiate a DRBG used by the TPM for normal operations.
10.2.16.2.10 DRBG_Uninstantiate()
10.2.17 CryptRsa.c
10.2.17.1 Introduction
This file contains implementation of cryptographic primitives for RSA. Vendors may replace the
implementation in this file with their own library functions.
10.2.17.2 Includes
Need this define to get the private defines for this function
1 #define CRYPT_RSA_C
2 #include "Tpm.h"
3 #if ALG_RSA
10.2.17.3.1 CryptRsaInit()
4 BOOL
5 CryptRsaInit(
6 void
7 )
8 {
9 return TRUE;
10 }
10.2.17.3.2 CryptRsaStartup()
11 BOOL
12 CryptRsaStartup(
13 void
14 )
15 {
16 return TRUE;
17 }
10.2.17.4.1 RsaInitializeExponent()
This function initializes the bignum data structure that holds the private exponent. This function returns
the pointer to the private exponent value so that it can be used in an initializer for a data declaration.
18 static privateExponent *
19 RsaInitializeExponent(
20 privateExponent *Z
21 )
22 {
23 bigNum *bn = (bigNum *)&Z->P;
24 int i;
25 //
10.2.17.4.2 MakePgreaterThanQ()
This function swaps the pointers for P and Q if Q happens to be larger than Q.
33 static void
34 MakePgreaterThanQ(
35 privateExponent *Z
36 )
37 {
38 if(BnUnsignedCmp(Z->P, Z->Q) < 0)
39 {
40 bigNum bnT = Z->P;
41 Z->P = Z->Q;
42 Z->Q = bnT;
43 }
44 }
10.2.17.4.3 PackExponent()
This function takes the bignum private exponent and converts it into TPM2B form. In this form, the size
field contains the overall size of the packed data. The buffer contains 5, equal sized values in P, Q, dP,
dQ, qInv order. For example, if a key has a 2Kb public key, then the packed private key will contain 5,
1Kb values. This form makes it relatively easy to load and save the values without changing the normal
unmarshaling to do anything more than allow a larger TPM2B for the private key. Also, when exporting
the value, all that is needed is to change the size field of the private key in order to save just the P value.
45 static BOOL
46 PackExponent(
47 TPM2B_PRIVATE_KEY_RSA *packed,
48 privateExponent *Z
49 )
50 {
51 int i;
52 UINT16 primeSize = (UINT16)BITS_TO_BYTES(BnMsb(Z->P));
53 UINT16 pS = primeSize;
54 //
55 pAssert((primeSize * 5) <= sizeof(packed->t.buffer));
56 packed->t.size = (primeSize * 5) + RSA_prime_flag;
57 for(i = 0; i < 5; i++)
58 if(!BnToBytes((bigNum)&Z->entries[i], &packed->t.buffer[primeSize * i], &pS))
59 return FALSE;
60 if(pS != primeSize)
61 return FALSE;
62 return TRUE;
63 }
10.2.17.4.4 UnpackExponent()
This function unpacks the private exponent from its TPM2B form into its bignum form.
64 static BOOL
65 UnpackExponent(
66 TPM2B_PRIVATE_KEY_RSA *b,
67 privateExponent *Z
68 )
69 {
70 UINT16 primeSize = b->t.size & ~RSA_prime_flag;
71 int i;
72 bigNum *bn = &Z->P;
73 //
74 VERIFY(b->t.size & RSA_prime_flag);
75 RsaInitializeExponent(Z);
76 VERIFY((primeSize % 5) == 0);
77 primeSize /= 5;
78 for(i = 0; i < 5; i++)
79 VERIFY(BnFromBytes(bn[i], &b->t.buffer[primeSize * i], primeSize)
80 != NULL);
81 MakePgreaterThanQ(Z);
82 return TRUE;
83 Error:
84 return FALSE;
85 }
10.2.17.4.5 ComputePrivateExponent()
86 static BOOL
87 ComputePrivateExponent(
88 bigNum pubExp, // IN: the public exponent
89 privateExponent *Z // IN/OUT: on input, has primes P and Q. On
90 // output, has P, Q, dP, dQ, and pInv
91 )
92 {
93 BOOL pOK;
94 BOOL qOK;
95 BN_PRIME(pT);
96 //
97 // make p the larger value so that m2 is always less than p
98 MakePgreaterThanQ(Z);
99
100 //dP = (1/e) mod (p-1)
101 pOK = BnSubWord(pT, Z->P, 1);
102 pOK = pOK && BnModInverse(Z->dP, pubExp, pT);
103 //dQ = (1/e) mod (q-1)
104 qOK = BnSubWord(pT, Z->Q, 1);
105 qOK = qOK && BnModInverse(Z->dQ, pubExp, pT);
106 // qInv = (1/q) mod p
10.2.17.4.6 RsaPrivateKeyOp()
This function is called to do the exponentiation with the private key. Compile options allow use of the
simple (but slow) private exponent, or the more complex but faster CRT method.
10.2.17.4.7 RSAEP()
This function performs the RSAEP operation defined in PKCS#1v2.1. It is an exponentiation of a value
(m) with the public exponent (e), modulo the public (n).
10.2.17.4.8 RSADP()
This function performs the RSADP operation defined in PKCS#1v2.1. It is an exponentiation of a value (c)
with the private exponent (d), modulo the public modulus (n). The decryption is in place.
This function also checks the size of the private key. If the size indicates that only a prime value is
present, the key is converted to being a private exponent.
10.2.17.4.9 OaepEncode()
This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must
equal the size of the modulus
10.2.17.4.10 OaepDecode()
This function performs OAEP padding checking. The size of the buffer to receive the recovered data. If
the padding is not valid, the dSize size is set to zero and the function returns TPM_RC_VALUE.
The dSize parameter is used as an input to indicate the size available in the buffer. If insufficient space is
available, the size is not changed and the return code is TPM_RC_VALUE.
300
301 // Recover the seed into seedMask
302 pAssert(hLen <= sizeof(seedMask));
303 pp = &padded->buffer[1];
304 pm = seedMask;
305 for(i = hLen; i > 0; i--)
306 *pm++ ^= *pp++;
307
308 // Use the seed to generate the data mask
309 CryptMGF1(padded->size - hLen - 1, mask, hashAlg, hLen, seedMask);
310
311 // Use the mask generated from seed to recover the padded data
312 pp = &padded->buffer[hLen + 1];
313 pm = mask;
314 for(i = (padded->size - hLen - 1); i > 0; i--)
315 *pm++ ^= *pp++;
316
317 // Make sure that the recovered data has the hash of the label
318 // Put trial value in the seed mask
319 if((CryptHashBlock(hashAlg, label->size, (BYTE *)label->buffer,
320 hLen, seedMask)) != hLen)
321 FAIL(FATAL_ERROR_INTERNAL);
322 if(memcmp(seedMask, mask, hLen) != 0)
323 ERROR_RETURN(TPM_RC_VALUE);
324
325 // find the start of the data
326 pm = &mask[hLen];
327 for(i = (UINT32)padded->size - (2 * hLen) - 1; i > 0; i--)
328 {
329 if(*pm++ != 0)
330 break;
331 }
332 // If we ran out of data or didn't end with 0x01, then return an error
333 if(i == 0 || pm[-1] != 0x01)
334 ERROR_RETURN(TPM_RC_VALUE);
335
336 // pm should be pointing at the first part of the data
337 // and i is one greater than the number of bytes to move
338 i--;
339 if(i > dataOut->size)
340 // Special exit to preserve the size of the output buffer
341 return TPM_RC_VALUE;
342 memcpy(dataOut->buffer, pm, i);
343 dataOut->size = (UINT16)i;
344 Exit:
345 if(retVal != TPM_RC_SUCCESS)
346 dataOut->size = 0;
347 return retVal;
348 }
10.2.17.4.11 PKCS1v1_5Encode()
355 {
356 UINT32 ps = padded->size - message->size - 3;
357 //
358 if(message->size > padded->size - 11)
359 return TPM_RC_VALUE;
360 // move the message to the end of the buffer
361 memcpy(&padded->buffer[padded->size - message->size], message->buffer,
362 message->size);
363 // Set the first byte to 0x00 and the second to 0x02
364 padded->buffer[0] = 0;
365 padded->buffer[1] = 2;
366
367 // Fill with random bytes
368 DRBG_Generate(rand, &padded->buffer[2], (UINT16)ps);
369 if(g_inFailureMode)
370 return TPM_RC_FAILURE;
371
372 // Set the delimiter for the random field to 0
373 padded->buffer[2 + ps] = 0;
374
375 // Now, the only messy part. Make sure that all the 'ps' bytes are non-zero
376 // In this implementation, use the value of the current index
377 for(ps++; ps > 1; ps--)
378 {
379 if(padded->buffer[ps] == 0)
380 padded->buffer[ps] = 0x55; // In the < 0.5% of the cases that the
381 // random value is 0, just pick a value to
382 // put into the spot.
383 }
384 return TPM_RC_SUCCESS;
385 }
10.2.17.4.12 RSAES_Decode()
10.2.17.4.13 CryptRsaPssSaltSize()
This function computes the salt size used in PSS. It is broken out so that the X509 code can get the same
value that is used by the encoding function in this module.
415 INT16
416 CryptRsaPssSaltSize(
417 INT16 hashSize,
418 INT16 outSize
419 )
420 {
421 INT16 saltSize;
422 //
423 // (Mask Length) = (outSize - hashSize - 1);
424 // Max saltSize is (Mask Length) - 1
425 saltSize = (outSize - hashSize - 1) - 1;
426 // Use the maximum salt size allowed by FIPS 186-4
427 if(saltSize > hashSize)
428 saltSize = hashSize;
429 else if(saltSize < 0)
430 saltSize = 0;
431 return saltSize;
432 }
10.2.17.4.14 PssEncode()
This function creates an encoded block of data that is the size of modulus. The function uses the
maximum salt size that will fit in the encoded block.
Returns TPM_RC_SUCCESS or goes into failure mode.
10.2.17.4.15 PssDecode()
This function checks that the PSS encoded block was built from the provided digest. If the check is
successful, TPM_RC_SUCCESS is returned. Any other value indicates an error.
This implementation of PSS decoding is intended for the reference TPM implementation and is not at all
generalized. It is used to check signatures over hashes and assumptions are made about the sizes of
values. Those assumptions are enforce by this implementation. This implementation does allow for a
variable size salt value to have been used by the creator of the signature.
572
573 // add the pad of 8 zeros
574 CryptDigestUpdate(&hashState, 8, pad);
575
576 // add the provided digest value
577 CryptDigestUpdate(&hashState, dIn->size, dIn->buffer);
578
579 // and the salt
580 CryptDigestUpdate(&hashState, i, pm);
581
582 // get the result
583 fail |= (CryptHashEnd(&hashState, hLen, mask) != hLen);
584
585 // Compare all bytes
586 for(pm = mask; hLen > 0; hLen--)
587 // don't use fail = because that could skip the increment and compare
588 // operations after the first failure and that gives away timing
589 // information.
590 fail |= *pm++ ^ *pe++;
591
592 retVal = (fail != 0) ? TPM_RC_VALUE : TPM_RC_SUCCESS;
593 Exit:
594 return retVal;
595 }
10.2.17.4.16 MakeDerTag()
596 INT16
597 MakeDerTag(
598 TPM_ALG_ID hashAlg,
599 INT16 sizeOfBuffer,
600 BYTE *buffer
601 )
602 {
603 // 0x30, 0x31, // SEQUENCE (2 elements) 1st
604 // 0x30, 0x0D, // SEQUENCE (2 elements)
605 // 0x06, 0x09, // HASH OID
606 // 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
607 // 0x05, 0x00, // NULL
608 // 0x04, 0x20 // OCTET STRING
609 HASH_DEF *info = CryptGetHashDef(hashAlg);
610 INT16 oidSize;
611 // If no OID, can't do encode
612 VERIFY(info != NULL);
613 oidSize = 2 + (info->OID)[1];
614 // make sure this fits in the buffer
615 VERIFY(sizeOfBuffer >= (oidSize + 8));
616 *buffer++ = 0x30; // 1st SEQUENCE
617 // Size of the 1st SEQUENCE is 6 bytes + size of the hash OID + size of the
618 // digest size
619 *buffer++ = (BYTE)(6 + oidSize + info->digestSize); //
620 *buffer++ = 0x30; // 2nd SEQUENCE
621 // size is 4 bytes of overhead plus the side of the OID
622 *buffer++ = (BYTE)(2 + oidSize);
623 MemoryCopy(buffer, info->OID, oidSize);
624 buffer += oidSize;
10.2.17.4.17 RSASSA_Encode()
10.2.17.4.18 RSASSA_Decode()
10.2.17.5.1 CryptRsaSelectScheme()
This function is used by TPM2_RSA_Decrypt() and TPM2_RSA_Encrypt(). It sets up the rules to select a
scheme between input and object default. This function assume the RSA object is loaded. If a default
scheme is defined in object, the default scheme should be chosen, otherwise, the input scheme should
be chosen. In the case that both the object and scheme are not TPM_ALG_NULL, then if the schemes
are the same, the input scheme will be chosen. if the scheme are not compatible, a NULL pointer will be
returned.
The return pointer may point to a TPM_ALG_NULL scheme.
728 TPMT_RSA_DECRYPT*
729 CryptRsaSelectScheme(
730 TPMI_DH_OBJECT rsaHandle, // IN: handle of an RSA key
731 TPMT_RSA_DECRYPT *scheme // IN: a sign or decrypt scheme
732 )
733 {
734 OBJECT *rsaObject;
735 TPMT_ASYM_SCHEME *keyScheme;
736 TPMT_RSA_DECRYPT *retVal = NULL;
737
738 // Get sign object pointer
739 rsaObject = HandleToObject(rsaHandle);
740 keyScheme = &rsaObject->publicArea.parameters.asymDetail.scheme;
741
742 // if the default scheme of the object is TPM_ALG_NULL, then select the
743 // input scheme
744 if(keyScheme->scheme == TPM_ALG_NULL)
745 {
746 retVal = scheme;
747 }
748 // if the object scheme is not TPM_ALG_NULL and the input scheme is
749 // TPM_ALG_NULL, then select the default scheme of the object.
750 else if(scheme->scheme == TPM_ALG_NULL)
751 {
752 // if input scheme is NULL
753 retVal = (TPMT_RSA_DECRYPT *)keyScheme;
754 }
755 // get here if both the object scheme and the input scheme are
756 // not TPM_ALG_NULL. Need to insure that they are the same.
757 // IMPLEMENTATION NOTE: This could cause problems if future versions have
758 // schemes that have more values than just a hash algorithm. A new function
759 // (IsSchemeSame()) might be needed then.
760 else if(keyScheme->scheme == scheme->scheme
761 && keyScheme->details.anySig.hashAlg == scheme->details.anySig.hashAlg)
762 {
763 retVal = scheme;
764 }
765 // two different, incompatible schemes specified will return NULL
766 return retVal;
767 }
10.2.17.5.2 CryptRsaLoadPrivateExponent()
768 TPM_RC
769 CryptRsaLoadPrivateExponent(
770 TPMT_PUBLIC *publicArea,
771 TPMT_SENSITIVE *sensitive
772 )
773 {
774 //
775 if((sensitive->sensitive.rsa.t.size & RSA_prime_flag) == 0)
776 {
777 if((sensitive->sensitive.rsa.t.size * 2) == publicArea->unique.rsa.t.size)
778 {
779 NEW_PRIVATE_EXPONENT(Z);
780 BN_RSA_INITIALIZED(bnN, &publicArea->unique.rsa);
781 BN_RSA(bnQr);
782 BN_VAR(bnE, RADIX_BITS);
783
784 TEST(ALG_NULL_VALUE);
785
786 VERIFY((sensitive->sensitive.rsa.t.size * 2)
787 == publicArea->unique.rsa.t.size);
788 // Initialize the exponent
789 BnSetWord(bnE, publicArea->parameters.rsaDetail.exponent);
790 if(BnEqualZero(bnE))
791 BnSetWord(bnE, RSA_DEFAULT_PUBLIC_EXPONENT);
792 // Convert first prime to 2B
793 VERIFY(BnFrom2B(Z->P, &sensitive->sensitive.rsa.b) != NULL);
794
795 // Find the second prime by division. This uses 'bQ' rather than Z->Q
796 // because the division could make the quotient larger than a prime during
797 // some intermediate step.
798 VERIFY(BnDiv(Z->Q, bnQr, bnN, Z->P));
799 VERIFY(BnEqualZero(bnQr));
800 // Compute the private exponent and return it if found
801 VERIFY(ComputePrivateExponent(bnE, Z));
802 VERIFY(PackExponent(&sensitive->sensitive.rsa, Z));
803 }
804 else
805 VERIFY(((sensitive->sensitive.rsa.t.size / 5) * 2)
806 == publicArea->unique.rsa.t.size);
807 sensitive->sensitive.rsa.t.size |= RSA_prime_flag;
808 }
809 return TPM_RC_SUCCESS;
810 Error:
811 return TPM_RC_BINDING;
812 }
10.2.17.5.3 CryptRsaEncrypt()
This is the entry point for encryption using RSA. Encryption is use of the public exponent. The padding
parameter determines what padding will be used.
The cOutSize parameter must be at least as large as the size of the key.
If the padding is RSA_PAD_NONE, dIn is treated as a number. It must be lower in value than the key
modulus.
NOTE: If dIn has fewer bytes than cOut, then we don't add low-order zeros to dIn to make it the size of the RSA key for
the call to RSAEP. This is because the high order bytes of dIn might have a numeric value that is greater than
the value of the key modulus. If this had low-order zeros added, it would have a numeric value larger than the
modulus even though it started out with a lower numeric value.
867 break;
868 default:
869 ERROR_RETURN(TPM_RC_SCHEME);
870 break;
871 }
872 // All the schemes that do padding will come here for the encryption step
873 // Check that the Encoding worked
874 if(retVal == TPM_RC_SUCCESS)
875 // Padding OK so do the encryption
876 retVal = RSAEP(&cOut->b, key);
877 Exit:
878 return retVal;
879 }
10.2.17.5.4 CryptRsaDecrypt()
This is the entry point for decryption using RSA. Decryption is use of the private exponent. The padType
parameter determines what padding was used.
10.2.17.5.5 CryptRsaSign()
This function is used to generate an RSA signature of the type indicated in scheme.
10.2.17.5.6 CryptRsaValidateSignature()
This function is used to validate an RSA signature. If the signature is valid TPM_RC_SUCCESS is
returned. If the signature is not valid, TPM_RC_SIGNATURE is returned. Other return codes indicate
either parameter problems or fatal errors.
10.2.17.5.7 CryptRsaGenerateKey()
10.2.18 CryptSmac.c
10.2.18.1 Introduction
This file contains the implementation of the message authentication codes based on a symmetric block
cipher. These functions only use the single block encryption functions of the selected symmetric
cryptographic library.
1 #define _CRYPT_HASH_C_
2 #include "Tpm.h"
3 #if SMAC_IMPLEMENTED
10.2.18.2.1 CryptSmacStart()
4 UINT16
5 CryptSmacStart(
6 HASH_STATE *state,
7 TPMU_PUBLIC_PARMS *keyParameters,
8 TPM_ALG_ID macAlg, // IN: the type of MAC
9 TPM2B *key
10 )
11 {
12 UINT16 retVal = 0;
13 //
14 // Make sure that the key size is correct. This should have been checked
15 // at key load, but...
16 if(BITS_TO_BYTES(keyParameters->symDetail.sym.keyBits.sym) == key->size)
17 {
18 switch(macAlg)
19 {
20 #if ALG_CMAC
21 case ALG_CMAC_VALUE:
22 retVal = CryptCmacStart(&state->state.smac, keyParameters,
23 macAlg, key);
24 break;
25 #endif
26 default:
27 break;
28 }
29 }
30 state->type = (retVal != 0) ? HASH_STATE_SMAC : HASH_STATE_EMPTY;
31 return retVal;
32 }
10.2.18.2.2 CryptMacStart()
Function to start either an HMAC or an SMAC. Cannot reuse the CryptHmacStart() function because of
the difference in number of parameters.
33 UINT16
34 CryptMacStart(
35 HMAC_STATE *state,
36 TPMU_PUBLIC_PARMS *keyParameters,
37 TPM_ALG_ID macAlg, // IN: the type of MAC
38 TPM2B *key
39 )
40 {
41 MemorySet(state, 0, sizeof(HMAC_STATE));
42 if(CryptHashIsValidAlg(macAlg, FALSE))
43 {
44 return CryptHmacStart(state, macAlg, key->size, key->buffer);
45 }
46 else if(CryptSmacIsValidAlg(macAlg, FALSE))
47 {
48 return CryptSmacStart(&state->hashState, keyParameters, macAlg, key);
49 }
50 else
51 return 0;
52 }
10.2.18.2.3 CryptMacEnd()
Dispatch to the MAC end function using a size and buffer pointer.
53 UINT16
54 CryptMacEnd(
55 HMAC_STATE *state,
56 UINT32 size,
57 BYTE *buffer
58 )
59 {
60 UINT16 retVal = 0;
61 if(state->hashState.type == HASH_STATE_SMAC)
62 retVal = (state->hashState.state.smac.smacMethods.end)(
63 &state->hashState.state.smac.state, size, buffer);
64 else if(state->hashState.type == HASH_STATE_HMAC)
65 retVal = CryptHmacEnd(state, size, buffer);
66 state->hashState.type = HASH_STATE_EMPTY;
67 return retVal;
68 }
10.2.18.2.4 CryptMacEnd2B()
69 UINT16
70 CryptMacEnd2B (
71 HMAC_STATE *state,
72 TPM2B *data
73 )
74 {
75 return CryptMacEnd(state, data->size, data->buffer);
76 }
77 #endif // SMAC_IMPLEMENTED
10.2.19 CryptSym.c
10.2.19.1 Introduction
This file contains the implementation of the symmetric block cipher modes allowed for a TPM. These
functions only use the single block encryption functions of the selected symmetric crypto library.
1 #include "Tpm.h"
2 #include "CryptSym.h"
3 #define KEY_BLOCK_SIZES(ALG, alg) \
4 static const INT16 alg##KeyBlockSizes[] = { \
5 ALG##_KEY_SIZES_BITS, -1, ALG##_BLOCK_SIZES };
6 #if ALG_AES
7 KEY_BLOCK_SIZES(AES, aes);
8 #endif // ALG_AES
9 #if ALG_SM4
10 KEY_BLOCK_SIZES(SM4, sm4);
11 #endif
12 #if ALG_CAMELLIA
13 KEY_BLOCK_SIZES(CAMELLIA, camellia);
14 #endif
15 #if ALG_TDES
16 KEY_BLOCK_SIZES(TDES, tdes);
17 #endif
10.2.19.3.1 CryptSymInit()
18 BOOL
19 CryptSymInit(
20 void
21 )
22 {
23 return TRUE;
24 }
10.2.19.3.2 CryptSymStartup()
25 BOOL
26 CryptSymStartup(
27 void
28 )
29 {
30 return TRUE;
31 }
10.2.19.3.3 CryptGetSymmetricBlockSize()
This function returns the block size of the algorithm. The table of bit sizes has an entry for each allowed
key size. The entry for a key size is 0 if the TPM does not implement that key size. The key size table is
delimited with a negative number (-1). After the delimiter is a list of block sizes with each entry
corresponding to the key bit size. For most symmetric algorithms, the block size is the same regardless of
the key size but this arrangement allows them to be different.
32 LIB_EXPORT INT16
33 CryptGetSymmetricBlockSize(
34 TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm
35 UINT16 keySizeInBits // IN: the key size
36 )
37 {
38 const INT16 *sizes;
39 INT16 i;
40 #define ALG_CASE(SYM, sym) case ALG_##SYM##_VALUE: sizes = sym##KeyBlockSizes; break
41 switch(symmetricAlg)
42 {
43 #if ALG_AES
44 ALG_CASE(AES, aes);
45 #endif
46 #if ALG_SM4
47 ALG_CASE(SM4, sm4);
48 #endif
49 #if ALG_CAMELLIA
50 ALG_CASE(CAMELLIA, camellia);
51 #endif
52 #if ALG_TDES
53 ALG_CASE(TDES, tdes);
54 #endif
55 default:
56 return 0;
57 }
58 // Find the index of the indicated keySizeInBits
59 for(i = 0; *sizes >= 0; i++, sizes++)
60 {
61 if(*sizes == keySizeInBits)
62 break;
63 }
64 // If sizes is pointing at the end of the list of key sizes, then the desired
65 // key size was not found so set the block size to zero.
66 if(*sizes++ < 0)
67 return 0;
68 // Advance until the end of the list is found
69 while(*sizes++ >= 0);
70 // sizes is pointing to the first entry in the list of block sizes. Use the
71 // ith index to find the block size for the corresponding key size.
72 return sizes[i];
73 }
74 LIB_EXPORT TPM_RC
75 CryptSymmetricEncrypt(
76 BYTE *dOut, // OUT:
77 TPM_ALG_ID algorithm, // IN: the symmetric algorithm
78 UINT16 keySizeInBits, // IN: key size in bits
79 const BYTE *key, // IN: key buffer. The size of this buffer
80 // in bytes is (keySizeInBits + 7) / 8
81 TPM2B_IV *ivInOut, // IN/OUT: IV for decryption.
82 TPM_ALG_ID mode, // IN: Mode to use
83 INT32 dSize, // IN: data size (may need to be a
84 // multiple of the blockSize)
85 const BYTE *dIn // IN: data buffer
86 )
87 {
88 BYTE *pIv;
89 int i;
90 BYTE tmp[MAX_SYM_BLOCK_SIZE];
91 BYTE *pT;
92 tpmCryptKeySchedule_t keySchedule;
93 INT16 blockSize;
94 TpmCryptSetSymKeyCall_t encrypt;
95 BYTE *iv;
96 BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0};
97 //
98 pAssert(dOut != NULL && key != NULL && dIn != NULL);
99 if(dSize == 0)
100 return TPM_RC_SUCCESS;
101
102 TEST(algorithm);
103 blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits);
104 if(blockSize == 0)
105 return TPM_RC_FAILURE;
106 // If the iv is provided, then it is expected to be block sized. In some cases,
107 // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE]
108 // with no knowledge of the actual block size. This function will set it.
109 if((ivInOut != NULL) && (mode != ALG_ECB_VALUE))
110 {
111 ivInOut->t.size = blockSize;
112 iv = ivInOut->t.buffer;
113 }
114 else
115 iv = defaultIv;
116 pIv = iv;
117
118 // Create encrypt key schedule and set the encryption function pointer.
119
120 SELECT(ENCRYPT);
121
122 switch(mode)
123 {
124 #if ALG_CTR
125 case ALG_CTR_VALUE:
126 for(; dSize > 0; dSize -= blockSize)
127 {
128 // Encrypt the current value of the IV(counter)
129 ENCRYPT(&keySchedule, iv, tmp);
130
131 //increment the counter (counter is big-endian so start at end)
10.2.19.4.1 CryptSymmetricDecrypt()
250 if(dSize == 0)
251 return TPM_RC_SUCCESS;
252
253 TEST(algorithm);
254 blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits);
255 if(blockSize == 0)
256 return TPM_RC_FAILURE;
257 // If the iv is provided, then it is expected to be block sized. In some cases,
258 // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE]
259 // with no knowledge of the actual block size. This function will set it.
260 if((ivInOut != NULL) && (mode != ALG_ECB_VALUE))
261 {
262 ivInOut->t.size = blockSize;
263 iv = ivInOut->t.buffer;
264 }
265 else
266 iv = defaultIv;
267
268 pIv = iv;
269 // Use the mode to select the key schedule to create. Encrypt always uses the
270 // encryption schedule. Depending on the mode, decryption might use either
271 // the decryption or encryption schedule.
272 switch(mode)
273 {
274 #if ALG_CBC || ALG_ECB
275 case ALG_CBC_VALUE: // decrypt = decrypt
276 case ALG_ECB_VALUE:
277 // For ECB and CBC, the data size must be an even multiple of the
278 // cipher block size
279 if((dSize % blockSize) != 0)
280 return TPM_RC_SIZE;
281 SELECT(DECRYPT);
282 break;
283 #endif
284 default:
285 // For the remaining stream ciphers, use encryption to decrypt
286 SELECT(ENCRYPT);
287 break;
288 }
289 // Now do the mode-dependent decryption
290 switch(mode)
291 {
292 #if ALG_CBC
293 case ALG_CBC_VALUE:
294 // Copy the input data to a temp buffer, decrypt the buffer into the
295 // output, XOR in the IV, and copy the temp buffer to the IV and repeat.
296 for(; dSize > 0; dSize -= blockSize)
297 {
298 pT = tmp;
299 for(i = blockSize; i > 0; i--)
300 *pT++ = *dIn++;
301 DECRYPT(&keySchedule, tmp, dOut);
302 pIv = iv;
303 pT = tmp;
304 for(i = blockSize; i > 0; i--)
305 {
306 *dOut++ ^= *pIv;
307 *pIv++ = *pT++;
308 }
309 }
310 break;
311 #endif
312 case ALG_CFB_VALUE:
313 for(; dSize > 0; dSize -= blockSize)
314 {
315 // Encrypt the IV into the temp buffer
10.2.19.4.2 CryptSymKeyValidate()
Validate that a provided symmetric key meets the requirements of the TPM
380 TPM_RC
381 CryptSymKeyValidate(
382 TPMT_SYM_DEF_OBJECT *symDef,
383 TPM2B_SYM_KEY *key
384 )
385 {
386 if(key->t.size != BITS_TO_BYTES(symDef->keyBits.sym))
387 return TPM_RCS_KEY_SIZE;
388 #if ALG_TDES
389 if(symDef->algorithm == TPM_ALG_TDES && !CryptDesValidateKey(key))
390 return TPM_RCS_KEY;
391 #endif // ALG_TDES
392 return TPM_RC_SUCCESS;
393 }
10.2.20 PrimeData.c
1 #include "Tpm.h"
This table is the product of all of the primes up to 1000. Checking to see if there is a GCD between a
prime candidate and this number will eliminate many prime candidates from consideration before running
Miller-Rabin on the result.
This table contains a bit for each of the odd values between 1 and 2^16 + 1. This table allows fast
checking of the primes in that range. Don't change the size of this table unless you are prepared to do
redo IsPrimeInt().
50 0x45, 0x08, 0x00, 0x08, 0x98, 0x36, 0x04, 0x52, 0x84, 0x04, 0xd0, 0x04,
51 0x00, 0x8a, 0x90, 0x44, 0x82, 0x32, 0x65, 0x18, 0x90, 0x00, 0x0a, 0x02,
52 0x01, 0x40, 0x02, 0x28, 0x40, 0xa4, 0x04, 0x92, 0x30, 0x04, 0x11, 0x86,
53 0x08, 0x42, 0x00, 0x2c, 0x52, 0x04, 0x08, 0xc9, 0x84, 0x60, 0x48, 0x12,
54 0x09, 0x99, 0x24, 0x44, 0x00, 0x24, 0x00, 0x03, 0x14, 0x21, 0x00, 0x10,
55 0x01, 0x1a, 0x32, 0x05, 0x88, 0x20, 0x40, 0x40, 0x06, 0x09, 0xc3, 0x84,
56 0x40, 0x01, 0x30, 0x60, 0x18, 0x02, 0x68, 0x11, 0x90, 0x0c, 0x02, 0xa2,
57 0x04, 0x00, 0x86, 0x29, 0x89, 0x14, 0x24, 0x82, 0x02, 0x41, 0x08, 0x80,
58 0x04, 0x19, 0x80, 0x08, 0x10, 0x12, 0x68, 0x42, 0xa4, 0x04, 0x00, 0x02,
59 0x61, 0x10, 0x06, 0x0c, 0x10, 0x00, 0x01, 0x12, 0x10, 0x20, 0x03, 0x94,
60 0x21, 0x42, 0x12, 0x65, 0x18, 0x94, 0x0c, 0x0a, 0x04, 0x28, 0x01, 0x14,
61 0x29, 0x0a, 0xa4, 0x40, 0xd0, 0x00, 0x40, 0x01, 0x90, 0x04, 0x41, 0x20,
62 0x2d, 0x40, 0x82, 0x48, 0xc1, 0x20, 0x00, 0x10, 0x30, 0x01, 0x08, 0x24,
63 0x04, 0x59, 0x84, 0x24, 0x00, 0x02, 0x29, 0x82, 0x00, 0x61, 0x58, 0x02,
64 0x48, 0x81, 0x16, 0x48, 0x10, 0x00, 0x21, 0x11, 0x06, 0x00, 0xca, 0xa0,
65 0x40, 0x02, 0x00, 0x04, 0x91, 0xb0, 0x00, 0x42, 0x04, 0x0c, 0x81, 0x06,
66 0x09, 0x48, 0x14, 0x25, 0x92, 0x20, 0x25, 0x11, 0xa0, 0x00, 0x0a, 0x86,
67 0x0c, 0xc1, 0x02, 0x48, 0x00, 0x20, 0x45, 0x08, 0x32, 0x00, 0x98, 0x06,
68 0x04, 0x13, 0x22, 0x00, 0x82, 0x04, 0x48, 0x81, 0x14, 0x44, 0x82, 0x12,
69 0x24, 0x18, 0x10, 0x40, 0x43, 0x80, 0x28, 0xd0, 0x04, 0x20, 0x81, 0x24,
70 0x64, 0xd8, 0x00, 0x2c, 0x09, 0x12, 0x08, 0x41, 0xa2, 0x00, 0x00, 0x02,
71 0x41, 0xca, 0x20, 0x41, 0xc0, 0x10, 0x01, 0x18, 0xa4, 0x04, 0x18, 0xa4,
72 0x20, 0x12, 0x94, 0x20, 0x83, 0xa0, 0x40, 0x02, 0x32, 0x44, 0x80, 0x04,
73 0x00, 0x18, 0x00, 0x0c, 0x40, 0x86, 0x60, 0x8a, 0x00, 0x64, 0x88, 0x12,
74 0x05, 0x01, 0x82, 0x00, 0x4a, 0xa2, 0x01, 0xc1, 0x10, 0x61, 0x09, 0x04,
75 0x01, 0x88, 0x00, 0x60, 0x01, 0xb4, 0x40, 0x08, 0x06, 0x01, 0x03, 0x80,
76 0x08, 0x40, 0x94, 0x04, 0x8a, 0x20, 0x29, 0x80, 0x02, 0x0c, 0x52, 0x02,
77 0x01, 0x42, 0x84, 0x00, 0x80, 0x84, 0x64, 0x02, 0x32, 0x48, 0x00, 0x30,
78 0x44, 0x40, 0x22, 0x21, 0x00, 0x02, 0x08, 0xc3, 0xa0, 0x04, 0xd0, 0x20,
79 0x40, 0x18, 0x16, 0x40, 0x40, 0x00, 0x28, 0x52, 0x90, 0x08, 0x82, 0x14,
80 0x01, 0x18, 0x10, 0x08, 0x09, 0x82, 0x40, 0x0a, 0xa0, 0x20, 0x93, 0x80,
81 0x08, 0xc0, 0x00, 0x20, 0x52, 0x00, 0x05, 0x01, 0x10, 0x40, 0x11, 0x06,
82 0x0c, 0x82, 0x00, 0x00, 0x4b, 0x90, 0x44, 0x9a, 0x00, 0x28, 0x80, 0x90,
83 0x04, 0x4a, 0x06, 0x09, 0x43, 0x02, 0x28, 0x00, 0x34, 0x01, 0x18, 0x00,
84 0x65, 0x09, 0x80, 0x44, 0x03, 0x00, 0x24, 0x02, 0x82, 0x61, 0x48, 0x14,
85 0x41, 0x00, 0x12, 0x28, 0x00, 0x34, 0x08, 0x51, 0x04, 0x05, 0x12, 0x90,
86 0x28, 0x89, 0x84, 0x60, 0x12, 0x10, 0x49, 0x10, 0x26, 0x40, 0x49, 0x82,
87 0x00, 0x91, 0x10, 0x01, 0x0a, 0x24, 0x40, 0x88, 0x10, 0x4c, 0x10, 0x04,
88 0x00, 0x50, 0xa2, 0x2c, 0x40, 0x90, 0x48, 0x0a, 0xb0, 0x01, 0x50, 0x12,
89 0x08, 0x00, 0xa4, 0x04, 0x09, 0xa0, 0x28, 0x92, 0x02, 0x00, 0x43, 0x10,
90 0x21, 0x02, 0x20, 0x41, 0x81, 0x32, 0x00, 0x08, 0x04, 0x0c, 0x52, 0x00,
91 0x21, 0x49, 0x84, 0x20, 0x10, 0x02, 0x01, 0x81, 0x10, 0x48, 0x40, 0x22,
92 0x01, 0x01, 0x84, 0x69, 0xc1, 0x30, 0x01, 0xc8, 0x02, 0x44, 0x88, 0x00,
93 0x0c, 0x01, 0x02, 0x2d, 0xc0, 0x12, 0x61, 0x00, 0xa0, 0x00, 0xc0, 0x30,
94 0x40, 0x01, 0x12, 0x08, 0x0b, 0x20, 0x00, 0x80, 0x94, 0x40, 0x01, 0x84,
95 0x40, 0x00, 0x32, 0x00, 0x10, 0x84, 0x00, 0x0b, 0x24, 0x00, 0x01, 0x06,
96 0x29, 0x8a, 0x84, 0x41, 0x80, 0x10, 0x08, 0x08, 0x94, 0x4c, 0x03, 0x80,
97 0x01, 0x40, 0x96, 0x40, 0x41, 0x20, 0x20, 0x50, 0x22, 0x25, 0x89, 0xa2,
98 0x40, 0x40, 0xa4, 0x20, 0x02, 0x86, 0x28, 0x01, 0x20, 0x21, 0x4a, 0x10,
99 0x08, 0x00, 0x14, 0x08, 0x40, 0x04, 0x25, 0x42, 0x02, 0x21, 0x43, 0x10,
100 0x04, 0x92, 0x00, 0x21, 0x11, 0xa0, 0x4c, 0x18, 0x22, 0x09, 0x03, 0x84,
101 0x41, 0x89, 0x10, 0x04, 0x82, 0x22, 0x24, 0x01, 0x14, 0x08, 0x08, 0x84,
102 0x08, 0xc1, 0x00, 0x09, 0x42, 0xb0, 0x41, 0x8a, 0x02, 0x00, 0x80, 0x36,
103 0x04, 0x49, 0xa0, 0x24, 0x91, 0x00, 0x00, 0x02, 0x94, 0x41, 0x92, 0x02,
104 0x01, 0x08, 0x06, 0x08, 0x09, 0x00, 0x01, 0xd0, 0x16, 0x28, 0x89, 0x80,
105 0x60, 0x00, 0x00, 0x68, 0x01, 0x90, 0x0c, 0x50, 0x20, 0x01, 0x40, 0x80,
106 0x40, 0x42, 0x30, 0x41, 0x00, 0x20, 0x25, 0x81, 0x06, 0x40, 0x49, 0x00,
107 0x08, 0x01, 0x12, 0x49, 0x00, 0xa0, 0x20, 0x18, 0x30, 0x05, 0x01, 0xa6,
108 0x00, 0x10, 0x24, 0x28, 0x00, 0x02, 0x20, 0xc8, 0x20, 0x00, 0x88, 0x12,
109 0x0c, 0x90, 0x92, 0x00, 0x02, 0x26, 0x01, 0x42, 0x16, 0x49, 0x00, 0x04,
110 0x24, 0x42, 0x02, 0x01, 0x88, 0x80, 0x0c, 0x1a, 0x80, 0x08, 0x10, 0x00,
111 0x60, 0x02, 0x94, 0x44, 0x88, 0x00, 0x69, 0x11, 0x30, 0x08, 0x12, 0xa0,
112 0x24, 0x13, 0x84, 0x00, 0x82, 0x00, 0x65, 0xc0, 0x10, 0x28, 0x00, 0x30,
113 0x04, 0x03, 0x20, 0x01, 0x11, 0x06, 0x01, 0xc8, 0x80, 0x00, 0xc2, 0x20,
114 0x08, 0x10, 0x82, 0x0c, 0x13, 0x02, 0x0c, 0x52, 0x06, 0x40, 0x00, 0xb0,
115 0x61, 0x40, 0x10, 0x01, 0x98, 0x86, 0x04, 0x10, 0x84, 0x08, 0x92, 0x14,
116 0x60, 0x41, 0x80, 0x41, 0x1a, 0x10, 0x04, 0x81, 0x22, 0x40, 0x41, 0x20,
117 0x29, 0x52, 0x00, 0x41, 0x08, 0x34, 0x60, 0x10, 0x00, 0x28, 0x01, 0x10,
118 0x40, 0x00, 0x84, 0x08, 0x42, 0x90, 0x20, 0x48, 0x04, 0x04, 0x52, 0x02,
119 0x00, 0x08, 0x20, 0x04, 0x00, 0x82, 0x0d, 0x00, 0x82, 0x40, 0x02, 0x10,
120 0x05, 0x48, 0x20, 0x40, 0x99, 0x00, 0x00, 0x01, 0x06, 0x24, 0xc0, 0x00,
121 0x68, 0x82, 0x04, 0x21, 0x12, 0x10, 0x44, 0x08, 0x04, 0x00, 0x40, 0xa6,
122 0x20, 0xd0, 0x16, 0x09, 0xc9, 0x24, 0x41, 0x02, 0x20, 0x0c, 0x09, 0x92,
123 0x40, 0x12, 0x00, 0x00, 0x40, 0x00, 0x09, 0x43, 0x84, 0x20, 0x98, 0x02,
124 0x01, 0x11, 0x24, 0x00, 0x43, 0x24, 0x00, 0x03, 0x90, 0x08, 0x41, 0x30,
125 0x24, 0x58, 0x20, 0x4c, 0x80, 0x82, 0x08, 0x10, 0x24, 0x25, 0x81, 0x06,
126 0x41, 0x09, 0x10, 0x20, 0x18, 0x10, 0x44, 0x80, 0x10, 0x00, 0x4a, 0x24,
127 0x0d, 0x01, 0x94, 0x28, 0x80, 0x30, 0x00, 0xc0, 0x02, 0x60, 0x10, 0x84,
128 0x0c, 0x02, 0x00, 0x09, 0x02, 0x82, 0x01, 0x08, 0x10, 0x04, 0xc2, 0x20,
129 0x68, 0x09, 0x06, 0x04, 0x18, 0x00, 0x00, 0x11, 0x90, 0x08, 0x0b, 0x10,
130 0x21, 0x82, 0x02, 0x0c, 0x10, 0xb6, 0x08, 0x00, 0x26, 0x00, 0x41, 0x02,
131 0x01, 0x4a, 0x24, 0x21, 0x1a, 0x20, 0x24, 0x80, 0x00, 0x44, 0x02, 0x00,
132 0x2d, 0x40, 0x02, 0x00, 0x8b, 0x94, 0x20, 0x10, 0x00, 0x20, 0x90, 0xa6,
133 0x40, 0x13, 0x00, 0x2c, 0x11, 0x86, 0x61, 0x01, 0x80, 0x41, 0x10, 0x02,
134 0x04, 0x81, 0x30, 0x48, 0x48, 0x20, 0x28, 0x50, 0x80, 0x21, 0x8a, 0x10,
135 0x04, 0x08, 0x10, 0x09, 0x10, 0x10, 0x48, 0x42, 0xa0, 0x0c, 0x82, 0x92,
136 0x60, 0xc0, 0x20, 0x05, 0xd2, 0x20, 0x40, 0x01, 0x00, 0x04, 0x08, 0x82,
137 0x2d, 0x82, 0x02, 0x00, 0x48, 0x80, 0x41, 0x48, 0x10, 0x00, 0x91, 0x04,
138 0x04, 0x03, 0x84, 0x00, 0xc2, 0x04, 0x68, 0x00, 0x00, 0x64, 0xc0, 0x22,
139 0x40, 0x08, 0x32, 0x44, 0x09, 0x86, 0x00, 0x91, 0x02, 0x28, 0x01, 0x00,
140 0x64, 0x48, 0x00, 0x24, 0x10, 0x90, 0x00, 0x43, 0x00, 0x21, 0x52, 0x86,
141 0x41, 0x8b, 0x90, 0x20, 0x40, 0x20, 0x08, 0x88, 0x04, 0x44, 0x13, 0x20,
142 0x00, 0x02, 0x84, 0x60, 0x81, 0x90, 0x24, 0x40, 0x30, 0x00, 0x08, 0x10,
143 0x08, 0x08, 0x02, 0x01, 0x10, 0x04, 0x20, 0x43, 0xb4, 0x40, 0x90, 0x12,
144 0x68, 0x01, 0x80, 0x4c, 0x18, 0x00, 0x08, 0xc0, 0x12, 0x49, 0x40, 0x10,
145 0x24, 0x1a, 0x00, 0x41, 0x89, 0x24, 0x4c, 0x10, 0x00, 0x04, 0x52, 0x10,
146 0x09, 0x4a, 0x20, 0x41, 0x48, 0x22, 0x69, 0x11, 0x14, 0x08, 0x10, 0x06,
147 0x24, 0x80, 0x84, 0x28, 0x00, 0x10, 0x00, 0x40, 0x10, 0x01, 0x08, 0x26,
148 0x08, 0x48, 0x06, 0x28, 0x00, 0x14, 0x01, 0x42, 0x84, 0x04, 0x0a, 0x20,
149 0x00, 0x01, 0x82, 0x08, 0x00, 0x82, 0x24, 0x12, 0x04, 0x40, 0x40, 0xa0,
150 0x40, 0x90, 0x10, 0x04, 0x90, 0x22, 0x40, 0x10, 0x20, 0x2c, 0x80, 0x10,
151 0x28, 0x43, 0x00, 0x04, 0x58, 0x00, 0x01, 0x81, 0x10, 0x48, 0x09, 0x20,
152 0x21, 0x83, 0x04, 0x00, 0x42, 0xa4, 0x44, 0x00, 0x00, 0x6c, 0x10, 0xa0,
153 0x44, 0x48, 0x80, 0x00, 0x83, 0x80, 0x48, 0xc9, 0x00, 0x00, 0x00, 0x02,
154 0x05, 0x10, 0xb0, 0x04, 0x13, 0x04, 0x29, 0x10, 0x92, 0x40, 0x08, 0x04,
155 0x44, 0x82, 0x22, 0x00, 0x19, 0x20, 0x00, 0x19, 0x20, 0x01, 0x81, 0x90,
156 0x60, 0x8a, 0x00, 0x41, 0xc0, 0x02, 0x45, 0x10, 0x04, 0x00, 0x02, 0xa2,
157 0x09, 0x40, 0x10, 0x21, 0x49, 0x20, 0x01, 0x42, 0x30, 0x2c, 0x00, 0x14,
158 0x44, 0x01, 0x22, 0x04, 0x02, 0x92, 0x08, 0x89, 0x04, 0x21, 0x80, 0x10,
159 0x05, 0x01, 0x20, 0x40, 0x41, 0x80, 0x04, 0x00, 0x12, 0x09, 0x40, 0xb0,
160 0x64, 0x58, 0x32, 0x01, 0x08, 0x90, 0x00, 0x41, 0x04, 0x09, 0xc1, 0x80,
161 0x61, 0x08, 0x90, 0x00, 0x9a, 0x00, 0x24, 0x01, 0x12, 0x08, 0x02, 0x26,
162 0x05, 0x82, 0x06, 0x08, 0x08, 0x00, 0x20, 0x48, 0x20, 0x00, 0x18, 0x24,
163 0x48, 0x03, 0x02, 0x00, 0x11, 0x00, 0x09, 0x00, 0x84, 0x01, 0x4a, 0x10,
164 0x01, 0x98, 0x00, 0x04, 0x18, 0x86, 0x00, 0xc0, 0x00, 0x20, 0x81, 0x80,
165 0x04, 0x10, 0x30, 0x05, 0x00, 0xb4, 0x0c, 0x4a, 0x82, 0x29, 0x91, 0x02,
166 0x28, 0x00, 0x20, 0x44, 0xc0, 0x00, 0x2c, 0x91, 0x80, 0x40, 0x01, 0xa2,
167 0x00, 0x12, 0x04, 0x09, 0xc3, 0x20, 0x00, 0x08, 0x02, 0x0c, 0x10, 0x22,
168 0x04, 0x00, 0x00, 0x2c, 0x11, 0x86, 0x00, 0xc0, 0x00, 0x00, 0x12, 0x32,
169 0x40, 0x89, 0x80, 0x40, 0x40, 0x02, 0x05, 0x50, 0x86, 0x60, 0x82, 0xa4,
170 0x60, 0x0a, 0x12, 0x4d, 0x80, 0x90, 0x08, 0x12, 0x80, 0x09, 0x02, 0x14,
171 0x48, 0x01, 0x24, 0x20, 0x8a, 0x00, 0x44, 0x90, 0x04, 0x04, 0x01, 0x02,
172 0x00, 0xd1, 0x12, 0x00, 0x0a, 0x04, 0x40, 0x00, 0x32, 0x21, 0x81, 0x24,
173 0x08, 0x19, 0x84, 0x20, 0x02, 0x04, 0x08, 0x89, 0x80, 0x24, 0x02, 0x02,
174 0x68, 0x18, 0x82, 0x44, 0x42, 0x00, 0x21, 0x40, 0x00, 0x28, 0x01, 0x80,
175 0x45, 0x82, 0x20, 0x40, 0x11, 0x80, 0x0c, 0x02, 0x00, 0x24, 0x40, 0x90,
176 0x01, 0x40, 0x20, 0x20, 0x50, 0x20, 0x28, 0x19, 0x00, 0x40, 0x09, 0x20,
177 0x08, 0x80, 0x04, 0x60, 0x40, 0x80, 0x20, 0x08, 0x30, 0x49, 0x09, 0x34,
178 0x00, 0x11, 0x24, 0x24, 0x82, 0x00, 0x41, 0xc2, 0x00, 0x04, 0x92, 0x02,
179 0x24, 0x80, 0x00, 0x0c, 0x02, 0xa0, 0x00, 0x01, 0x06, 0x60, 0x41, 0x04,
180 0x21, 0xd0, 0x00, 0x01, 0x01, 0x00, 0x48, 0x12, 0x84, 0x04, 0x91, 0x12,
181 0x08, 0x00, 0x24, 0x44, 0x00, 0x12, 0x41, 0x18, 0x26, 0x0c, 0x41, 0x80,
182 0x00, 0x52, 0x04, 0x20, 0x09, 0x00, 0x24, 0x90, 0x20, 0x48, 0x18, 0x02,
183 0x00, 0x03, 0xa2, 0x09, 0xd0, 0x14, 0x00, 0x8a, 0x84, 0x25, 0x4a, 0x00,
184 0x20, 0x98, 0x14, 0x40, 0x00, 0xa2, 0x05, 0x00, 0x00, 0x00, 0x40, 0x14,
185 0x01, 0x58, 0x20, 0x2c, 0x80, 0x84, 0x00, 0x09, 0x20, 0x20, 0x91, 0x02,
186 0x08, 0x02, 0xb0, 0x41, 0x08, 0x30, 0x00, 0x09, 0x10, 0x00, 0x18, 0x02,
187 0x21, 0x02, 0x02, 0x00, 0x00, 0x24, 0x44, 0x08, 0x12, 0x60, 0x00, 0xb2,
188 0x44, 0x12, 0x02, 0x0c, 0xc0, 0x80, 0x40, 0xc8, 0x20, 0x04, 0x50, 0x20,
189 0x05, 0x00, 0xb0, 0x04, 0x0b, 0x04, 0x29, 0x53, 0x00, 0x61, 0x48, 0x30,
190 0x00, 0x82, 0x20, 0x29, 0x00, 0x16, 0x00, 0x53, 0x22, 0x20, 0x43, 0x10,
191 0x48, 0x00, 0x80, 0x04, 0xd2, 0x00, 0x40, 0x00, 0xa2, 0x44, 0x03, 0x80,
192 0x29, 0x00, 0x04, 0x08, 0xc0, 0x04, 0x64, 0x40, 0x30, 0x28, 0x09, 0x84,
193 0x44, 0x50, 0x80, 0x21, 0x02, 0x92, 0x00, 0xc0, 0x10, 0x60, 0x88, 0x22,
194 0x08, 0x80, 0x00, 0x00, 0x18, 0x84, 0x04, 0x83, 0x96, 0x00, 0x81, 0x20,
195 0x05, 0x02, 0x00, 0x45, 0x88, 0x84, 0x00, 0x51, 0x20, 0x20, 0x51, 0x86,
196 0x41, 0x4b, 0x94, 0x00, 0x80, 0x00, 0x08, 0x11, 0x20, 0x4c, 0x58, 0x80,
197 0x04, 0x03, 0x06, 0x20, 0x89, 0x00, 0x05, 0x08, 0x22, 0x05, 0x90, 0x00,
198 0x40, 0x00, 0x82, 0x09, 0x50, 0x00, 0x00, 0x00, 0xa0, 0x41, 0xc2, 0x20,
199 0x08, 0x00, 0x16, 0x08, 0x40, 0x26, 0x21, 0xd0, 0x90, 0x08, 0x81, 0x90,
200 0x41, 0x00, 0x02, 0x44, 0x08, 0x10, 0x0c, 0x0a, 0x86, 0x09, 0x90, 0x04,
201 0x00, 0xc8, 0xa0, 0x04, 0x08, 0x30, 0x20, 0x89, 0x84, 0x00, 0x11, 0x22,
202 0x2c, 0x40, 0x00, 0x08, 0x02, 0xb0, 0x01, 0x48, 0x02, 0x01, 0x09, 0x20,
203 0x04, 0x03, 0x04, 0x00, 0x80, 0x02, 0x60, 0x42, 0x30, 0x21, 0x4a, 0x10,
204 0x44, 0x09, 0x02, 0x00, 0x01, 0x24, 0x00, 0x12, 0x82, 0x21, 0x80, 0xa4,
205 0x20, 0x10, 0x02, 0x04, 0x91, 0xa0, 0x40, 0x18, 0x04, 0x00, 0x02, 0x06,
206 0x69, 0x09, 0x00, 0x05, 0x58, 0x02, 0x01, 0x00, 0x00, 0x48, 0x00, 0x00,
207 0x00, 0x03, 0x92, 0x20, 0x00, 0x34, 0x01, 0xc8, 0x20, 0x48, 0x08, 0x30,
208 0x08, 0x42, 0x80, 0x20, 0x91, 0x90, 0x68, 0x01, 0x04, 0x40, 0x12, 0x02,
209 0x61, 0x00, 0x12, 0x08, 0x01, 0xa0, 0x00, 0x11, 0x04, 0x21, 0x48, 0x04,
210 0x24, 0x92, 0x00, 0x0c, 0x01, 0x84, 0x04, 0x00, 0x00, 0x01, 0x12, 0x96,
211 0x40, 0x01, 0xa0, 0x41, 0x88, 0x22, 0x28, 0x88, 0x00, 0x44, 0x42, 0x80,
212 0x24, 0x12, 0x14, 0x01, 0x42, 0x90, 0x60, 0x1a, 0x10, 0x04, 0x81, 0x10,
213 0x48, 0x08, 0x06, 0x29, 0x83, 0x02, 0x40, 0x02, 0x24, 0x64, 0x80, 0x10,
214 0x05, 0x80, 0x10, 0x40, 0x02, 0x02, 0x08, 0x42, 0x84, 0x01, 0x09, 0x20,
215 0x04, 0x50, 0x00, 0x60, 0x11, 0x30, 0x40, 0x13, 0x02, 0x04, 0x81, 0x00,
216 0x09, 0x08, 0x20, 0x45, 0x4a, 0x10, 0x61, 0x90, 0x26, 0x0c, 0x08, 0x02,
217 0x21, 0x91, 0x00, 0x60, 0x02, 0x04, 0x00, 0x02, 0x00, 0x0c, 0x08, 0x06,
218 0x08, 0x48, 0x84, 0x08, 0x11, 0x02, 0x00, 0x80, 0xa4, 0x00, 0x5a, 0x20,
219 0x00, 0x88, 0x04, 0x04, 0x02, 0x00, 0x09, 0x00, 0x14, 0x08, 0x49, 0x14,
220 0x20, 0xc8, 0x00, 0x04, 0x91, 0xa0, 0x40, 0x59, 0x80, 0x00, 0x12, 0x10,
221 0x00, 0x80, 0x80, 0x65, 0x00, 0x00, 0x04, 0x00, 0x80, 0x40, 0x19, 0x00,
222 0x21, 0x03, 0x84, 0x60, 0xc0, 0x04, 0x24, 0x1a, 0x12, 0x61, 0x80, 0x80,
223 0x08, 0x02, 0x04, 0x09, 0x42, 0x12, 0x20, 0x08, 0x34, 0x04, 0x90, 0x20,
224 0x01, 0x01, 0xa0, 0x00, 0x0b, 0x00, 0x08, 0x91, 0x92, 0x40, 0x02, 0x34,
225 0x40, 0x88, 0x10, 0x61, 0x19, 0x02, 0x00, 0x40, 0x04, 0x25, 0xc0, 0x80,
226 0x68, 0x08, 0x04, 0x21, 0x80, 0x22, 0x04, 0x00, 0xa0, 0x0c, 0x01, 0x84,
227 0x20, 0x41, 0x00, 0x08, 0x8a, 0x00, 0x20, 0x8a, 0x00, 0x48, 0x88, 0x04,
228 0x04, 0x11, 0x82, 0x08, 0x40, 0x86, 0x09, 0x49, 0xa4, 0x40, 0x00, 0x10,
229 0x01, 0x01, 0xa2, 0x04, 0x50, 0x80, 0x0c, 0x80, 0x00, 0x48, 0x82, 0xa0,
230 0x01, 0x18, 0x12, 0x41, 0x01, 0x04, 0x48, 0x41, 0x00, 0x24, 0x01, 0x00,
231 0x00, 0x88, 0x14, 0x00, 0x02, 0x00, 0x68, 0x01, 0x20, 0x08, 0x4a, 0x22,
232 0x08, 0x83, 0x80, 0x00, 0x89, 0x04, 0x01, 0xc2, 0x00, 0x00, 0x00, 0x34,
233 0x04, 0x00, 0x82, 0x28, 0x02, 0x02, 0x41, 0x4a, 0x90, 0x05, 0x82, 0x02,
234 0x09, 0x80, 0x24, 0x04, 0x41, 0x00, 0x01, 0x92, 0x80, 0x28, 0x01, 0x14,
235 0x00, 0x50, 0x20, 0x4c, 0x10, 0xb0, 0x04, 0x43, 0xa4, 0x21, 0x90, 0x04,
236 0x01, 0x02, 0x00, 0x44, 0x48, 0x00, 0x64, 0x08, 0x06, 0x00, 0x42, 0x20,
237 0x08, 0x02, 0x92, 0x01, 0x4a, 0x00, 0x20, 0x50, 0x32, 0x25, 0x90, 0x22,
238 0x04, 0x09, 0x00, 0x08, 0x11, 0x80, 0x21, 0x01, 0x10, 0x05, 0x00, 0x32,
239 0x08, 0x88, 0x94, 0x08, 0x08, 0x24, 0x0d, 0xc1, 0x80, 0x40, 0x0b, 0x20,
240 0x40, 0x18, 0x12, 0x04, 0x00, 0x22, 0x40, 0x10, 0x26, 0x05, 0xc1, 0x82,
241 0x00, 0x01, 0x30, 0x24, 0x02, 0x22, 0x41, 0x08, 0x24, 0x48, 0x1a, 0x00,
242 0x25, 0xd2, 0x12, 0x28, 0x42, 0x00, 0x04, 0x40, 0x30, 0x41, 0x00, 0x02,
243 0x00, 0x13, 0x20, 0x24, 0xd1, 0x84, 0x08, 0x89, 0x80, 0x04, 0x52, 0x00,
244 0x44, 0x18, 0xa4, 0x00, 0x00, 0x06, 0x20, 0x91, 0x10, 0x09, 0x42, 0x20,
245 0x24, 0x40, 0x30, 0x28, 0x00, 0x84, 0x40, 0x40, 0x80, 0x08, 0x10, 0x04,
246 0x09, 0x08, 0x04, 0x40, 0x08, 0x22, 0x00, 0x19, 0x02, 0x00, 0x00, 0x80,
247 0x2c, 0x02, 0x02, 0x21, 0x01, 0x90, 0x20, 0x40, 0x00, 0x0c, 0x00, 0x34,
248 0x48, 0x58, 0x20, 0x01, 0x43, 0x04, 0x20, 0x80, 0x14, 0x00, 0x90, 0x00,
249 0x6d, 0x11, 0x00, 0x00, 0x40, 0x20, 0x00, 0x03, 0x10, 0x40, 0x88, 0x30,
250 0x05, 0x4a, 0x00, 0x65, 0x10, 0x24, 0x08, 0x18, 0x84, 0x28, 0x03, 0x80,
251 0x20, 0x42, 0xb0, 0x40, 0x00, 0x10, 0x69, 0x19, 0x04, 0x00, 0x00, 0x80,
252 0x04, 0xc2, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x22, 0x25, 0x08, 0x96,
253 0x04, 0x02, 0x22, 0x00, 0xd0, 0x10, 0x29, 0x01, 0xa0, 0x60, 0x08, 0x10,
254 0x04, 0x01, 0x16, 0x44, 0x10, 0x02, 0x28, 0x02, 0x82, 0x48, 0x40, 0x84,
255 0x20, 0x90, 0x22, 0x28, 0x80, 0x04, 0x00, 0x40, 0x04, 0x24, 0x00, 0x80,
256 0x29, 0x03, 0x10, 0x60, 0x48, 0x00, 0x00, 0x81, 0xa0, 0x00, 0x51, 0x20,
257 0x0c, 0xd1, 0x00, 0x01, 0x41, 0x20, 0x04, 0x92, 0x00, 0x00, 0x10, 0x92,
258 0x00, 0x42, 0x04, 0x05, 0x01, 0x86, 0x40, 0x80, 0x10, 0x20, 0x52, 0x20,
259 0x21, 0x00, 0x10, 0x48, 0x0a, 0x02, 0x00, 0xd0, 0x12, 0x41, 0x48, 0x80,
260 0x04, 0x00, 0x00, 0x48, 0x09, 0x22, 0x04, 0x00, 0x24, 0x00, 0x43, 0x10,
261 0x60, 0x0a, 0x00, 0x44, 0x12, 0x20, 0x2c, 0x08, 0x20, 0x44, 0x00, 0x84,
262 0x09, 0x40, 0x06, 0x08, 0xc1, 0x00, 0x40, 0x80, 0x20, 0x00, 0x98, 0x12,
263 0x48, 0x10, 0xa2, 0x20, 0x00, 0x84, 0x48, 0xc0, 0x10, 0x20, 0x90, 0x12,
264 0x08, 0x98, 0x82, 0x00, 0x0a, 0xa0, 0x04, 0x03, 0x00, 0x28, 0xc3, 0x00,
265 0x44, 0x42, 0x10, 0x04, 0x08, 0x04, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00,
266 0x21, 0x03, 0x80, 0x04, 0x88, 0x12, 0x69, 0x10, 0x00, 0x04, 0x08, 0x04,
267 0x04, 0x02, 0x84, 0x48, 0x49, 0x04, 0x20, 0x18, 0x02, 0x64, 0x80, 0x30,
268 0x08, 0x01, 0x02, 0x00, 0x52, 0x12, 0x49, 0x08, 0x20, 0x41, 0x88, 0x10,
269 0x48, 0x08, 0x34, 0x00, 0x01, 0x86, 0x05, 0xd0, 0x00, 0x00, 0x83, 0x84,
270 0x21, 0x40, 0x02, 0x41, 0x10, 0x80, 0x48, 0x40, 0xa2, 0x20, 0x51, 0x00,
271 0x00, 0x49, 0x00, 0x01, 0x90, 0x20, 0x40, 0x18, 0x02, 0x40, 0x02, 0x22,
272 0x05, 0x40, 0x80, 0x08, 0x82, 0x10, 0x20, 0x18, 0x00, 0x05, 0x01, 0x82,
273 0x40, 0x58, 0x00, 0x04, 0x81, 0x90, 0x29, 0x01, 0xa0, 0x64, 0x00, 0x22,
274 0x40, 0x01, 0xa2, 0x00, 0x18, 0x04, 0x0d, 0x00, 0x00, 0x60, 0x80, 0x94,
275 0x60, 0x82, 0x10, 0x0d, 0x80, 0x30, 0x0c, 0x12, 0x20, 0x00, 0x00, 0x12,
276 0x40, 0xc0, 0x20, 0x21, 0x58, 0x02, 0x41, 0x10, 0x80, 0x44, 0x03, 0x02,
277 0x04, 0x13, 0x90, 0x29, 0x08, 0x00, 0x44, 0xc0, 0x00, 0x21, 0x00, 0x26,
278 0x00, 0x1a, 0x80, 0x01, 0x13, 0x14, 0x20, 0x0a, 0x14, 0x20, 0x00, 0x32,
279 0x61, 0x08, 0x00, 0x40, 0x42, 0x20, 0x09, 0x80, 0x06, 0x01, 0x81, 0x80,
280 0x60, 0x42, 0x00, 0x68, 0x90, 0x82, 0x08, 0x42, 0x80, 0x04, 0x02, 0x80,
281 0x09, 0x0b, 0x04, 0x00, 0x98, 0x00, 0x0c, 0x81, 0x06, 0x44, 0x48, 0x84,
282 0x28, 0x03, 0x92, 0x00, 0x01, 0x80, 0x40, 0x0a, 0x00, 0x0c, 0x81, 0x02,
283 0x08, 0x51, 0x04, 0x28, 0x90, 0x02, 0x20, 0x09, 0x10, 0x60, 0x00, 0x00,
284 0x09, 0x81, 0xa0, 0x0c, 0x00, 0xa4, 0x09, 0x00, 0x02, 0x28, 0x80, 0x20,
285 0x00, 0x02, 0x02, 0x04, 0x81, 0x14, 0x04, 0x00, 0x04, 0x09, 0x11, 0x12,
286 0x60, 0x40, 0x20, 0x01, 0x48, 0x30, 0x40, 0x11, 0x00, 0x08, 0x0a, 0x86,
287 0x00, 0x00, 0x04, 0x60, 0x81, 0x04, 0x01, 0xd0, 0x02, 0x41, 0x18, 0x90,
288 0x00, 0x0a, 0x20, 0x00, 0xc1, 0x06, 0x01, 0x08, 0x80, 0x64, 0xca, 0x10,
289 0x04, 0x99, 0x80, 0x48, 0x01, 0x82, 0x20, 0x50, 0x90, 0x48, 0x80, 0x84,
290 0x20, 0x90, 0x22, 0x00, 0x19, 0x00, 0x04, 0x18, 0x20, 0x24, 0x10, 0x86,
291 0x40, 0xc2, 0x00, 0x24, 0x12, 0x10, 0x44, 0x00, 0x16, 0x08, 0x10, 0x24,
292 0x00, 0x12, 0x06, 0x01, 0x08, 0x90, 0x00, 0x12, 0x02, 0x4d, 0x10, 0x80,
293 0x40, 0x50, 0x22, 0x00, 0x43, 0x10, 0x01, 0x00, 0x30, 0x21, 0x0a, 0x00,
294 0x00, 0x01, 0x14, 0x00, 0x10, 0x84, 0x04, 0xc1, 0x10, 0x29, 0x0a, 0x00,
295 0x01, 0x8a, 0x00, 0x20, 0x01, 0x12, 0x0c, 0x49, 0x20, 0x04, 0x81, 0x00,
296 0x48, 0x01, 0x04, 0x60, 0x80, 0x12, 0x0c, 0x08, 0x10, 0x48, 0x4a, 0x04,
297 0x28, 0x10, 0x00, 0x28, 0x40, 0x84, 0x45, 0x50, 0x10, 0x60, 0x10, 0x06,
298 0x44, 0x01, 0x80, 0x09, 0x00, 0x86, 0x01, 0x42, 0xa0, 0x00, 0x90, 0x00,
299 0x05, 0x90, 0x22, 0x40, 0x41, 0x00, 0x08, 0x80, 0x02, 0x08, 0xc0, 0x00,
300 0x01, 0x58, 0x30, 0x49, 0x09, 0x14, 0x00, 0x41, 0x02, 0x0c, 0x02, 0x80,
301 0x40, 0x89, 0x00, 0x24, 0x08, 0x10, 0x05, 0x90, 0x32, 0x40, 0x0a, 0x82,
302 0x08, 0x00, 0x12, 0x61, 0x00, 0x04, 0x21, 0x00, 0x22, 0x04, 0x10, 0x24,
303 0x08, 0x0a, 0x04, 0x01, 0x10, 0x00, 0x20, 0x40, 0x84, 0x04, 0x88, 0x22,
304 0x20, 0x90, 0x12, 0x00, 0x53, 0x06, 0x24, 0x01, 0x04, 0x40, 0x0b, 0x14,
305 0x60, 0x82, 0x02, 0x0d, 0x10, 0x90, 0x0c, 0x08, 0x20, 0x09, 0x00, 0x14,
306 0x09, 0x80, 0x80, 0x24, 0x82, 0x00, 0x40, 0x01, 0x02, 0x44, 0x01, 0x20,
307 0x0c, 0x40, 0x84, 0x40, 0x0a, 0x10, 0x41, 0x00, 0x30, 0x05, 0x09, 0x80,
308 0x44, 0x08, 0x20, 0x20, 0x02, 0x00, 0x49, 0x43, 0x20, 0x21, 0x00, 0x20,
309 0x00, 0x01, 0xb6, 0x08, 0x40, 0x04, 0x08, 0x02, 0x80, 0x01, 0x41, 0x80,
310 0x40, 0x08, 0x10, 0x24, 0x00, 0x20, 0x04, 0x12, 0x86, 0x09, 0xc0, 0x12,
311 0x21, 0x81, 0x14, 0x04, 0x00, 0x02, 0x20, 0x89, 0xb4, 0x44, 0x12, 0x80,
312 0x00, 0xd1, 0x00, 0x69, 0x40, 0x80, 0x00, 0x42, 0x12, 0x00, 0x18, 0x04,
313 0x00, 0x49, 0x06, 0x21, 0x02, 0x04, 0x28, 0x02, 0x84, 0x01, 0xc0, 0x10,
314 0x68, 0x00, 0x20, 0x08, 0x40, 0x00, 0x08, 0x91, 0x10, 0x01, 0x81, 0x24,
315 0x04, 0xd2, 0x10, 0x4c, 0x88, 0x86, 0x00, 0x10, 0x80, 0x0c, 0x02, 0x14,
316 0x00, 0x8a, 0x90, 0x40, 0x18, 0x20, 0x21, 0x80, 0xa4, 0x00, 0x58, 0x24,
317 0x20, 0x10, 0x10, 0x60, 0xc1, 0x30, 0x41, 0x48, 0x02, 0x48, 0x09, 0x00,
318 0x40, 0x09, 0x02, 0x05, 0x11, 0x82, 0x20, 0x4a, 0x20, 0x24, 0x18, 0x02,
319 0x0c, 0x10, 0x22, 0x0c, 0x0a, 0x04, 0x00, 0x03, 0x06, 0x48, 0x48, 0x04,
320 0x04, 0x02, 0x00, 0x21, 0x80, 0x84, 0x00, 0x18, 0x00, 0x0c, 0x02, 0x12,
321 0x01, 0x00, 0x14, 0x05, 0x82, 0x10, 0x41, 0x89, 0x12, 0x08, 0x40, 0xa4,
322 0x21, 0x01, 0x84, 0x48, 0x02, 0x10, 0x60, 0x40, 0x02, 0x28, 0x00, 0x14,
323 0x08, 0x40, 0xa0, 0x20, 0x51, 0x12, 0x00, 0xc2, 0x00, 0x01, 0x1a, 0x30,
324 0x40, 0x89, 0x12, 0x4c, 0x02, 0x80, 0x00, 0x00, 0x14, 0x01, 0x01, 0xa0,
325 0x21, 0x18, 0x22, 0x21, 0x18, 0x06, 0x40, 0x01, 0x80, 0x00, 0x90, 0x04,
326 0x48, 0x02, 0x30, 0x04, 0x08, 0x00, 0x05, 0x88, 0x24, 0x08, 0x48, 0x04,
327 0x24, 0x02, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0x10, 0x65, 0x11, 0x90,
328 0x00, 0x0a, 0x82, 0x04, 0xc3, 0x04, 0x60, 0x48, 0x24, 0x04, 0x92, 0x02,
329 0x44, 0x88, 0x80, 0x40, 0x18, 0x06, 0x29, 0x80, 0x10, 0x01, 0x00, 0x00,
330 0x44, 0xc8, 0x10, 0x21, 0x89, 0x30, 0x00, 0x4b, 0xa0, 0x01, 0x10, 0x14,
331 0x00, 0x02, 0x94, 0x40, 0x00, 0x20, 0x65, 0x00, 0xa2, 0x0c, 0x40, 0x22,
332 0x20, 0x81, 0x12, 0x20, 0x82, 0x04, 0x01, 0x10, 0x00, 0x08, 0x88, 0x00,
333 0x00, 0x11, 0x80, 0x04, 0x42, 0x80, 0x40, 0x41, 0x14, 0x00, 0x40, 0x32,
334 0x2c, 0x80, 0x24, 0x04, 0x19, 0x00, 0x00, 0x91, 0x00, 0x20, 0x83, 0x00,
335 0x05, 0x40, 0x20, 0x09, 0x01, 0x84, 0x40, 0x40, 0x20, 0x20, 0x11, 0x00,
336 0x40, 0x41, 0x90, 0x20, 0x00, 0x00, 0x40, 0x90, 0x92, 0x48, 0x18, 0x06,
337 0x08, 0x81, 0x80, 0x48, 0x01, 0x34, 0x24, 0x10, 0x20, 0x04, 0x00, 0x20,
338 0x04, 0x18, 0x06, 0x2d, 0x90, 0x10, 0x01, 0x00, 0x90, 0x00, 0x0a, 0x22,
339 0x01, 0x00, 0x22, 0x00, 0x11, 0x84, 0x01, 0x01, 0x00, 0x20, 0x88, 0x00,
340 0x44, 0x00, 0x22, 0x01, 0x00, 0xa6, 0x40, 0x02, 0x06, 0x20, 0x11, 0x00,
341 0x01, 0xc8, 0xa0, 0x04, 0x8a, 0x00, 0x28, 0x19, 0x80, 0x00, 0x52, 0xa0,
342 0x24, 0x12, 0x12, 0x09, 0x08, 0x24, 0x01, 0x48, 0x00, 0x04, 0x00, 0x24,
343 0x40, 0x02, 0x84, 0x08, 0x00, 0x04, 0x48, 0x40, 0x90, 0x60, 0x0a, 0x22,
344 0x01, 0x88, 0x14, 0x08, 0x01, 0x02, 0x08, 0xd3, 0x00, 0x20, 0xc0, 0x90,
345 0x24, 0x10, 0x00, 0x00, 0x01, 0xb0, 0x08, 0x0a, 0xa0, 0x00, 0x80, 0x00,
346 0x01, 0x09, 0x00, 0x20, 0x52, 0x02, 0x25, 0x00, 0x24, 0x04, 0x02, 0x84,
347 0x24, 0x10, 0x92, 0x40, 0x02, 0xa0, 0x40, 0x00, 0x22, 0x08, 0x11, 0x04,
348 0x08, 0x01, 0x22, 0x00, 0x42, 0x14, 0x00, 0x09, 0x90, 0x21, 0x00, 0x30,
349 0x6c, 0x00, 0x00, 0x0c, 0x00, 0x22, 0x09, 0x90, 0x10, 0x28, 0x40, 0x00,
350 0x20, 0xc0, 0x20, 0x00, 0x90, 0x00, 0x40, 0x01, 0x82, 0x05, 0x12, 0x12,
351 0x09, 0xc1, 0x04, 0x61, 0x80, 0x02, 0x28, 0x81, 0x24, 0x00, 0x49, 0x04,
352 0x08, 0x10, 0x86, 0x29, 0x41, 0x80, 0x21, 0x0a, 0x30, 0x49, 0x88, 0x90,
353 0x00, 0x41, 0x04, 0x29, 0x81, 0x80, 0x41, 0x09, 0x00, 0x40, 0x12, 0x10,
354 0x40, 0x00, 0x10, 0x40, 0x48, 0x02, 0x05, 0x80, 0x02, 0x21, 0x40, 0x20,
355 0x00, 0x58, 0x20, 0x60, 0x00, 0x90, 0x48, 0x00, 0x80, 0x28, 0xc0, 0x80,
356 0x48, 0x00, 0x00, 0x44, 0x80, 0x02, 0x00, 0x09, 0x06, 0x00, 0x12, 0x02,
357 0x01, 0x00, 0x10, 0x08, 0x83, 0x10, 0x45, 0x12, 0x00, 0x2c, 0x08, 0x04,
358 0x44, 0x00, 0x20, 0x20, 0xc0, 0x10, 0x20, 0x01, 0x00, 0x05, 0xc8, 0x20,
359 0x04, 0x98, 0x10, 0x08, 0x10, 0x00, 0x24, 0x02, 0x16, 0x40, 0x88, 0x00,
360 0x61, 0x88, 0x12, 0x24, 0x80, 0xa6, 0x00, 0x42, 0x00, 0x08, 0x10, 0x06,
361 0x48, 0x40, 0xa0, 0x00, 0x50, 0x20, 0x04, 0x81, 0xa4, 0x40, 0x18, 0x00,
362 0x08, 0x10, 0x80, 0x01, 0x01};
363
364 #if RSA_KEY_SIEVE && SIMULATION && RSA_INSTRUMENT
365 UINT32 PrimeIndex = 0;
366 UINT32 failedAtIteration[10] = {0};
367 UINT32 PrimeCounts[3] = {0};
368 UINT32 MillerRabinTrials[3] = {0};
369 UINT32 totalFieldsSieved[3] = {0};
370 UINT32 bitsInFieldAfterSieve[3] = {0};
371 UINT32 emptyFieldsSieved[3] = {0};
372 UINT32 noPrimeFields[3] = {0};
373 UINT32 primesChecked[3] = {0};
374 UINT16 lastSievePrime = 0;
375 #endif
10.2.21 RsaKeyCache.c
10.2.21.1 Introduction
This file contains the functions to implement the RSA key cache that can be used to speed up simulation.
Only one key is created for each supported key size and it is returned whenever a key of that size is
requested.
If desired, the key cache can be populated from a file. This allows multiple TPM to run with the same RSA
keys. Also, when doing simulation, the DRBG will use preset sequences so it is not too hard to repeat
sequences for debug or profile or stress.
When the key cache is enabled, a call to CryptRsaGenerateKey() will call the GetCachedRsaKey(). If the
cache is enabled and populated, then the cached key of the requested size is returned. If a key of the
requested size is not available, the no key is loaded and the requested key will need to be generated. If
the cache is not populated, the TPM will open a file that has the appropriate name for the type of keys
required (CRT or no-CRT). If the file is the right size, it is used. If the file doesn't exist or the file does not
have the correct size, the TMP will populate the cache with new keys of the required size and write the
cache data to the file so that they will be available the next time.
Currently, if two simulations are being run with TPM's that have different RSA key sizes (e.g,, one with
1024 and 2048 and another with 2048 and 3072, then the files will not match for the both of them and
they will both try to overwrite the other's cache file. I may try to do something about this if necessary.
1 #include "Tpm.h"
2 #if USE_RSA_KEY_CACHE
3 #include <stdio.h>
4 #include "RsaKeyCache_fp.h"
5 #if CRT_FORMAT_RSA == YES
6 #define CACHE_FILE_NAME "RsaKeyCacheCrt.data"
7 #else
8 #define CACHE_FILE_NAME "RsaKeyCacheNoCrt.data"
9 #endif
10 typedef struct _RSA_KEY_CACHE_
11 {
12 TPM2B_PUBLIC_KEY_RSA publicModulus;
13 TPM2B_PRIVATE_KEY_RSA privateExponent;
14 } RSA_KEY_CACHE;
15 TPMI_RSA_KEY_BITS SupportedRsaKeySizes[] = {
16 #if RSA_1024
17 1024,
18 #endif
19 #if RSA_2048
20 2048,
21 #endif
22 #if RSA_3072
23 3072,
24 #endif
25 #if RSA_4096
26 4096,
27 #endif
28 0
29 };
30
31 #define RSA_KEY_CACHE_ENTRIES (RSA_1024 + RSA_2048 + RSA_3072 + RSA_4096)
The key cache holds one entry for each of the supported key sizes
32 RSA_KEY_CACHE s_rsaKeyCache[RSA_KEY_CACHE_ENTRIES];
33 // Indicates if the key cache is loaded. It can be loaded and enabled or disabled.
34 BOOL s_keyCacheLoaded = 0;
35
36 // Indicates if the key cache is enabled
37 int s_rsaKeyCacheEnabled = FALSE;
38
39 //*** RsaKeyCacheControl()
40 // Used to enable and disable the RSA key cache.
41 LIB_EXPORT void
42 RsaKeyCacheControl(
43 int state
44 )
45 {
46 s_rsaKeyCacheEnabled = state;
47 }
10.2.21.2.1 InitializeKeyCache()
This will initialize the key cache and attempt to write it to a file for later use.
48 static BOOL
49 InitializeKeyCache(
50 TPMT_PUBLIC *publicArea,
51 TPMT_SENSITIVE *sensitive,
52 RAND_STATE *rand // IN: if not NULL, the deterministic
53 // RNG state
54 )
55 {
56 int index;
57 TPM_KEY_BITS keySave = publicArea->parameters.rsaDetail.keyBits;
58 BOOL OK = TRUE;
59 //
60 s_rsaKeyCacheEnabled = FALSE;
61 for(index = 0; OK && index < RSA_KEY_CACHE_ENTRIES; index++)
62 {
63 publicArea->parameters.rsaDetail.keyBits
64 = SupportedRsaKeySizes[index];
65 OK = (CryptRsaGenerateKey(publicArea, sensitive, rand) == TPM_RC_SUCCESS);
66 if(OK)
67 {
68 s_rsaKeyCache[index].publicModulus = publicArea->unique.rsa;
69 s_rsaKeyCache[index].privateExponent = sensitive->sensitive.rsa;
70 }
71 }
72 publicArea->parameters.rsaDetail.keyBits = keySave;
73 s_keyCacheLoaded = OK;
74 #if SIMULATION && USE_RSA_KEY_CACHE && USE_KEY_CACHE_FILE
75 if(OK)
76 {
77 FILE *cacheFile;
78 const char *fn = CACHE_FILE_NAME;
79
80 #if defined _MSC_VER
81 if(fopen_s(&cacheFile, fn, "w+b") != 0)
82 #else
10.2.21.2.2 KeyCacheLoaded()
136 if(!s_keyCacheLoaded)
137 s_rsaKeyCacheEnabled = InitializeKeyCache(publicArea, sensitive, rand);
138 return s_keyCacheLoaded;
139 }
10.2.21.2.3 GetCachedRsaKey()
140 BOOL
141 GetCachedRsaKey(
142 TPMT_PUBLIC *publicArea,
143 TPMT_SENSITIVE *sensitive,
144 RAND_STATE *rand // IN: if not NULL, the deterministic
145 // RNG state
146 )
147 {
148 int keyBits = publicArea->parameters.rsaDetail.keyBits;
149 int index;
150 //
151 if(KeyCacheLoaded(publicArea, sensitive, rand))
152 {
153 for(index = 0; index < RSA_KEY_CACHE_ENTRIES; index++)
154 {
155 if((s_rsaKeyCache[index].publicModulus.t.size * 8) == keyBits)
156 {
157 publicArea->unique.rsa = s_rsaKeyCache[index].publicModulus;
158 sensitive->sensitive.rsa = s_rsaKeyCache[index].privateExponent;
159 return TRUE;
160 }
161 }
162 return FALSE;
163 }
164 return s_keyCacheLoaded;
165 }
166 #endif // defined SIMULATION && defined USE_RSA_KEY_CACHE
10.2.22 Ticket.c
10.2.22.1 Introduction
10.2.22.2 Includes
1 #include "Tpm.h"
10.2.22.3 Functions
10.2.22.3.1 TicketIsSafe()
This function indicates if producing a ticket is safe. It checks if the leading bytes of an input buffer is
TPM_GENERATED_VALUE or its substring of canonical form. If so, it is not safe to produce ticket for an
input buffer claiming to be TPM generated buffer
2 BOOL
3 TicketIsSafe(
4 TPM2B *buffer
5 )
6 {
7 TPM_GENERATED valueToCompare = TPM_GENERATED_VALUE;
8 BYTE bufferToCompare[sizeof(valueToCompare)];
9 BYTE *marshalBuffer;
10 //
11 // If the buffer size is less than the size of TPM_GENERATED_VALUE, assume
12 // it is not safe to generate a ticket
13 if(buffer->size < sizeof(valueToCompare))
14 return FALSE;
15 marshalBuffer = bufferToCompare;
16 TPM_GENERATED_Marshal(&valueToCompare, &marshalBuffer, NULL);
17 if(MemoryEqual(buffer->buffer, bufferToCompare, sizeof(valueToCompare)))
18 return FALSE;
19 else
20 return TRUE;
21 }
10.2.22.3.2 TicketComputeVerified()
22 void
23 TicketComputeVerified(
24 TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
25 TPM2B_DIGEST *digest, // IN: digest
26 TPM2B_NAME *keyName, // IN: name of key that signed the values
27 TPMT_TK_VERIFIED *ticket // OUT: verified ticket
28 )
29 {
30 TPM2B_PROOF *proof;
31 HMAC_STATE hmacState;
32 //
33 // Fill in ticket fields
34 ticket->tag = TPM_ST_VERIFIED;
35 ticket->hierarchy = hierarchy;
36 proof = HierarchyGetProof(hierarchy);
37
38 // Start HMAC using the proof value of the hierarchy as the HMAC key
39 ticket->digest.t.size = CryptHmacStart2B(&hmacState, CONTEXT_INTEGRITY_HASH_ALG,
40 &proof->b);
41 // TPM_ST_VERIFIED
42 CryptDigestUpdateInt(&hmacState, sizeof(TPM_ST), ticket->tag);
43 // digest
44 CryptDigestUpdate2B(&hmacState.hashState, &digest->b);
45 // key name
46 CryptDigestUpdate2B(&hmacState.hashState, &keyName->b);
47 // done
48 CryptHmacEnd2B(&hmacState, &ticket->digest.b);
49
50 return;
51 }
10.2.22.3.3 TicketComputeAuth()
52 void
53 TicketComputeAuth(
54 TPM_ST type, // IN: the type of ticket.
55 TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
56 UINT64 timeout, // IN: timeout
57 BOOL expiresOnReset,// IN: flag to indicate if ticket expires on
58 // TPM Reset
59 TPM2B_DIGEST *cpHashA, // IN: input cpHashA
60 TPM2B_NONCE *policyRef, // IN: input policyRef
61 TPM2B_NAME *entityName, // IN: name of entity
62 TPMT_TK_AUTH *ticket // OUT: Created ticket
63 )
64 {
65 TPM2B_PROOF *proof;
66 HMAC_STATE hmacState;
67 //
68 // Get proper proof
69 proof = HierarchyGetProof(hierarchy);
70
71 // Fill in ticket fields
72 ticket->tag = type;
73 ticket->hierarchy = hierarchy;
74
75 // Start HMAC with hierarchy proof as the HMAC key
76 ticket->digest.t.size = CryptHmacStart2B(&hmacState, CONTEXT_INTEGRITY_HASH_ALG,
77 &proof->b);
78 // TPM_ST_AUTH_SECRET or TPM_ST_AUTH_SIGNED,
79 CryptDigestUpdateInt(&hmacState, sizeof(UINT16), ticket->tag);
80 // cpHash
81 CryptDigestUpdate2B(&hmacState.hashState, &cpHashA->b);
82 // policyRef
83 CryptDigestUpdate2B(&hmacState.hashState, &policyRef->b);
84 // keyName
85 CryptDigestUpdate2B(&hmacState.hashState, &entityName->b);
86 // timeout
87 CryptDigestUpdateInt(&hmacState, sizeof(timeout), timeout);
88 if(timeout != 0)
89 {
90 // epoch
91 CryptDigestUpdateInt(&hmacState.hashState, sizeof(CLOCK_NONCE),
92 g_timeEpoch);
93 // reset count
94 if(expiresOnReset)
95 CryptDigestUpdateInt(&hmacState.hashState, sizeof(gp.totalResetCount),
96 gp.totalResetCount);
97 }
98 // done
99 CryptHmacEnd2B(&hmacState, &ticket->digest.b);
100
101 return;
102 }
10.2.22.3.4 TicketComputeHashCheck()
103 void
104 TicketComputeHashCheck(
105 TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
106 TPM_ALG_ID hashAlg, // IN: the hash algorithm for 'digest'
107 TPM2B_DIGEST *digest, // IN: input digest
108 TPMT_TK_HASHCHECK *ticket // OUT: Created ticket
109 )
110 {
111 TPM2B_PROOF *proof;
112 HMAC_STATE hmacState;
113 //
114 // Get proper proof
115 proof = HierarchyGetProof(hierarchy);
116
117 // Fill in ticket fields
118 ticket->tag = TPM_ST_HASHCHECK;
119 ticket->hierarchy = hierarchy;
120
121 // Start HMAC using hierarchy proof as HMAC key
122 ticket->digest.t.size = CryptHmacStart2B(&hmacState, CONTEXT_INTEGRITY_HASH_ALG,
123 &proof->b);
124 // TPM_ST_HASHCHECK
125 CryptDigestUpdateInt(&hmacState, sizeof(TPM_ST), ticket->tag);
126 // hash algorithm
127 CryptDigestUpdateInt(&hmacState, sizeof(hashAlg), hashAlg);
128 // digest
129 CryptDigestUpdate2B(&hmacState.hashState, &digest->b);
130 // done
131 CryptHmacEnd2B(&hmacState, &ticket->digest.b);
132
133 return;
134 }
10.2.22.3.5 TicketComputeCreation()
135 void
136 TicketComputeCreation(
137 TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy for ticket
138 TPM2B_NAME *name, // IN: object name
139 TPM2B_DIGEST *creation, // IN: creation hash
140 TPMT_TK_CREATION *ticket // OUT: created ticket
141 )
142 {
143 TPM2B_PROOF *proof;
10.2.23 TpmAsn1.c
10.2.23.1 Includes
1 #include "Tpm.h"
2 #define _OIDS_
3 #include "OIDs.h"
4 #include "TpmASN1.h"
5 #include "TpmASN1_fp.h"
10.2.23.2.1 ASN1UnmarshalContextInitialize()
6 BOOL
7 ASN1UnmarshalContextInitialize(
8 ASN1UnmarshalContext *ctx,
9 INT16 size,
10 BYTE *buffer
11 )
12 {
13 VERIFY(buffer != NULL);
14 VERIFY(size > 0);
15 ctx->buffer = buffer;
16 ctx->size = size;
17 ctx->offset = 0;
18 ctx->tag = 0xFF;
19 return TRUE;
20 Error:
21 return FALSE;
22 }
10.2.23.2.2 ASN1DecodeLength()
This function extracts the length of an element from buffer starting at offset.
23 INT16
24 ASN1DecodeLength(
25 ASN1UnmarshalContext *ctx
26 )
27 {
28 BYTE first; // Next octet in buffer
29 INT16 value;
30 //
31 VERIFY(ctx->offset < ctx->size);
32 first = NEXT_OCTET(ctx);
33 // If the number of octets of the entity is larger than 127, then the first octet
34 // is the number of octets in the length specifier.
35 if(first >= 0x80)
36 {
37 // Make sure that this length field is contained with the structure being
38 // parsed
39 CHECK_SIZE(ctx, (first & 0x7F));
40 if(first == 0x82)
41 {
42 // Two octets of size
43 // get the next value
44 value = (INT16)NEXT_OCTET(ctx);
45 // Make sure that the result will fit in an INT16
46 VERIFY(value < 0x0080);
47 // Shift up and add next octet
48 value = (value << 8) + NEXT_OCTET(ctx);
49 }
50 else if(first == 0x81)
51 value = NEXT_OCTET(ctx);
52 // Sizes larger than will fit in a INT16 are an error
53 else
54 goto Error;
55 }
56 else
57 value = first;
58 // Make sure that the size defined something within the current context
59 CHECK_SIZE(ctx, value);
60 return value;
61 Error:
62 ctx->size = -1; // Makes everything fail from now on.
63 return -1;
64 }
10.2.23.2.3 ASN1NextTag()
This function extracts the next type from buffer starting at offset. It advances offset as it parses the type
and the length of the type. It returns the length of the type. On return, the length octets starting at offset
are the octets of the type.
65 INT16
66 ASN1NextTag(
67 ASN1UnmarshalContext *ctx
68 )
69 {
70 // A tag to get?
71 VERIFY(ctx->offset < ctx->size);
72 // Get it
73 ctx->tag = NEXT_OCTET(ctx);
74 // Make sure that it is not an extended tag
75 VERIFY((ctx->tag & 0x1F) != 0x1F);
76 // Get the length field and return that
77 return ASN1DecodeLength(ctx);
78
79 Error:
80 // Attempt to read beyond the end of the context or an illegal tag
81 ctx->size = -1; // Persistent failure
82 ctx->tag = 0xFF;
83 return -1;
84 }
10.2.23.2.4 ASN1GetBitStringValue()
Try to parse a bit string of up to 32 bits from a value that is expected to be a bit string. The bit string is left
justified so that the MSb of the input is the MSb of the returned value. If there is a general parsing error,
the context->size is set to -1.
85 BOOL
86 ASN1GetBitStringValue(
87 ASN1UnmarshalContext *ctx,
88 UINT32 *val
89 )
90 {
91 int shift;
92 INT16 length;
93 UINT32 value = 0;
94 int inputBits;
95 //
96 length = ASN1NextTag(ctx);
97 VERIFY(length >= 1);
98 VERIFY(ctx->tag == ASN1_BITSTRING);
99 // Get the shift value for the bit field (how many bits to lop off of the end)
100 shift = NEXT_OCTET(ctx);
101 length--;
102 // Get the number of bits in the input
103 inputBits = (8 * length) - shift;
104 // the shift count has to make sense
105 VERIFY((shift < 8) && ((length > 0) || (shift == 0)));
106 // if there are any bytes left
107 for(; length > 1; length--)
108 {
109
110 // for all but the last octet, just shift and add the new octet
111 VERIFY((value & 0xFF000000) == 0); // can't loose significant bits
112 value = (value << 8) + NEXT_OCTET(ctx);
113
114 }
115 if(length == 1)
116 {
117 // for the last octet, just shift the accumulated value enough to
118 // accept the significant bits in the last octet and shift the last
119 // octet down
120 VERIFY(((value & (0xFF000000 << (8 - shift)))) == 0);
121 value = (value << (8 - shift)) + (NEXT_OCTET(ctx) >> shift);
122
123 }
124 // 'Left justify' the result
125 if(inputBits > 0)
126 value <<= (32 - inputBits);
127 *val = value;
128 return TRUE;
129 Error:
130 ctx->size = -1;
131 return FALSE;
132 }
10.2.23.3.1 Introduction
Marshaling of an ASN.1 structure is accomplished from the bottom up. That is, the things that will be at
the end of the structure are added last. To manage the collecting of the relative sizes, start a context for
the outermost container, if there is one, and then placing items in from the bottom up. If the bottom-most
item is also within a structure, create a nested context by calling ASN1StartMarshalingContext().
The context control structure contains a buffer pointer, an offset, an end and a stack. offset is the offset
from the start of the buffer of the last added byte. When offset reaches 0, the buffer is full. offset is a
signed value so that, when it becomes negative, there is an overflow. Only two functions are allowed to
move bytes into the buffer: ASN1PushByte() and ASN1PushBytes(). These functions make sure that no
data is written beyond the end of the buffer.
When a new context is started, the current value of end is pushed on the stack and end is set to 'offset.
As bytes are added, offset gets smaller. At any time, the count of bytes in the current context is simply
end - offset.
Since starting a new context involves setting end = offset, the number of bytes in the context starts at 0.
The nominal way of ending a context is to use end - offset to set the length value, and then a tag is added
to the buffer. Then the previous end value is popped meaning that the context just ended becomes a
member of the now current context.
The nominal strategy for building a completed ASN.1 structure is to push everything into the buffer and
then move everything to the start of the buffer. The move is simple as the size of the move is the initial
end value minus the final offset value. The destination is buffer and the source is buffer + offset. As
Skippy would say "Easy peasy, Joe."
It is not necessary to provide a buffer into which the data is placed. If no buffer is provided, then the
marshaling process will return values needed for marshaling. On strategy for filling the buffer would be to
execute the process for building the structure without using a buffer. This would return the overall size of
the structure. Then that amount of data could be allocated for the buffer and the fill process executed
again with the data going into the buffer. At the end, the data would be in its final resting place.
10.2.23.3.2 ASN1InitialializeMarshalContext()
This creates a structure for handling marshaling of an ASN.1 formatted data structure.
133 void
134 ASN1InitialializeMarshalContext(
135 ASN1MarshalContext *ctx,
136 INT16 length,
137 BYTE *buffer
138 )
139 {
140 ctx->buffer = buffer;
141 if(buffer)
142 ctx->offset = length;
143 else
144 ctx->offset = INT16_MAX;
145 ctx->end = ctx->offset;
146 ctx->depth = -1;
147 }
10.2.23.3.3 ASN1StartMarshalContext()
This starts a new constructed element. It is constructed on top of the value that was previously placed in
the structure.
148 void
149 ASN1StartMarshalContext(
150 ASN1MarshalContext *ctx
151 )
152 {
153 pAssert((ctx->depth + 1) < MAX_DEPTH);
154 ctx->depth++;
155 ctx->ends[ctx->depth] = ctx->end;
156 ctx->end = ctx->offset;
157 }
10.2.23.3.4 ASN1EndMarshalContext()
158 INT16
159 ASN1EndMarshalContext(
160 ASN1MarshalContext *ctx
161 )
162 {
163 INT16 length;
164 pAssert(ctx->depth >= 0);
165 length = ctx->end - ctx->offset;
166 ctx->end = ctx->ends[ctx->depth--];
167 if((ctx->depth == -1) && (ctx->buffer))
168 {
169 MemoryCopy(ctx->buffer, ctx->buffer + ctx->offset, ctx->end - ctx->offset);
170 }
171 return length;
172 }
10.2.23.3.5 ASN1EndEncapsulation()
This function puts a tag and length in the buffer. In this function, an embedded BIT_STRING is assumed
to be a collection of octets. To indicate that all bits are used, a byte of zero is prepended. If a raw bit-
string is needed, a new function like ASN1PushInteger() would be needed.
173 UINT16
174 ASN1EndEncapsulation(
175 ASN1MarshalContext *ctx,
176 BYTE tag
177 )
178 {
179 // only add a leading zero for an encapsulated BIT STRING
180 if (tag == ASN1_BITSTRING)
181 ASN1PushByte(ctx, 0);
182 ASN1PushTagAndLength(ctx, tag, ctx->end - ctx->offset);
183 return ASN1EndMarshalContext(ctx);
184 }
10.2.23.3.6 ASN1PushByte()
185 BOOL
186 ASN1PushByte(
187 ASN1MarshalContext *ctx,
188 BYTE b
189 )
190 {
191 if(ctx->offset > 0)
192 {
193 ctx->offset -= 1;
194 if(ctx->buffer)
195 ctx->buffer[ctx->offset] = b;
196 return TRUE;
197 }
198 ctx->offset = -1;
199 return FALSE;
200 }
10.2.23.3.7 ASN1PushBytes()
Push some raw bytes onto the buffer. count cannot be zero.
201 INT16
202 ASN1PushBytes(
203 ASN1MarshalContext *ctx,
204 INT16 count,
205 const BYTE *buffer
206 )
207 {
208 // make sure that count is not negative which would mess up the math; and that
209 // if there is a count, there is a buffer
210 VERIFY((count >= 0) && ((buffer != NULL) || (count == 0)));
211 // back up the offset to determine where the new octets will get pushed
212 ctx->offset -= count;
213 // can't go negative
214 VERIFY(ctx->offset >= 0);
215 // if there are buffers, move the data, otherwise, assume that this is just a
216 // test.
217 if(count && buffer && ctx->buffer)
218 MemoryCopy(&ctx->buffer[ctx->offset], buffer, count);
219 return count;
220 Error:
221 ctx->offset = -1;
222 return 0;
223 }
10.2.23.3.8 ASN1PushNull()
224 INT16
225 ASN1PushNull(
226 ASN1MarshalContext *ctx
227 )
228 {
229 ASN1PushByte(ctx, 0);
230 ASN1PushByte(ctx, ASN1_NULL);
231 return (ctx->offset >= 0) ? 2 : 0;
232 }
10.2.23.3.9 ASN1PushLength()
Push a length value. This will only handle length values that fit in an INT16.
233 INT16
234 ASN1PushLength(
235 ASN1MarshalContext *ctx,
236 INT16 len
237 )
238 {
239 UINT16 start = ctx->offset;
240 VERIFY(len >= 0);
241 if(len <= 127)
242 ASN1PushByte(ctx, (BYTE)len);
243 else
244 {
245 ASN1PushByte(ctx, (BYTE)(len & 0xFF));
246 len >>= 8;
247 if(len == 0)
248 ASN1PushByte(ctx, 0x81);
249 else
250 {
251 ASN1PushByte(ctx, (BYTE)(len));
252 ASN1PushByte(ctx, 0x82);
253 }
254 }
255 goto Exit;
256 Error:
257 ctx->offset = -1;
258 Exit:
259 return (ctx->offset > 0) ? start - ctx->offset : 0;
260 }
10.2.23.3.10 ASN1PushTagAndLength()
261 INT16
262 ASN1PushTagAndLength(
263 ASN1MarshalContext *ctx,
264 BYTE tag,
265 INT16 length
266 )
267 {
10.2.23.3.11 ASN1PushTaggedOctetString()
273 INT16
274 ASN1PushTaggedOctetString(
275 ASN1MarshalContext *ctx,
276 INT16 size,
277 const BYTE *string,
278 BYTE tag
279 )
280 {
281 ASN1PushBytes(ctx, size, string);
282 // PushTagAndLenght just tells how many octets it added so the total size of this
283 // element is the sum of those octets and input size.
284 size += ASN1PushTagAndLength(ctx, tag, size);
285 return size;
286 }
10.2.23.3.12 ASN1PushUINT()
This function pushes an native-endian integer value. This just changes a native-endian integer into a big-
endian byte string and calls ASN1PushInteger(). That function will remove leading zeros and make sure
that the number is positive.
287 INT16
288 ASN1PushUINT(
289 ASN1MarshalContext *ctx,
290 UINT32 integer
291 )
292 {
293 BYTE marshaled[4];
294 UINT32_TO_BYTE_ARRAY(integer, marshaled);
295 return ASN1PushInteger(ctx, 4, marshaled);
296 }
10.2.23.3.13 ASN1PushInteger
297 INT16
298 ASN1PushInteger(
299 ASN1MarshalContext *ctx, // IN/OUT: buffer context
300 INT16 iLen, // IN: octets of the integer
301 BYTE *integer // IN: big-endian integer
302 )
303 {
304 // no leading 0's
305 while((*integer == 0) && (--iLen > 0))
306 integer++;
307 // Move the bytes to the buffer
308 ASN1PushBytes(ctx, iLen, integer);
309 // if needed, add a leading byte of 0 to make the number positive
310 if(*integer & 0x80)
311 iLen += (INT16)ASN1PushByte(ctx, 0);
312 // PushTagAndLenght just tells how many octets it added so the total size of this
313 // element is the sum of those octets and the adjusted input size.
314 iLen += ASN1PushTagAndLength(ctx, ASN1_INTEGER, iLen);
315 return iLen;
316 }
10.2.23.3.14 ASN1PushOID()
This function is used to add an OID. An OID is 0x06 followed by a byte of size followed by size bytes.
This is used to avoid having to do anything special in the definition of an OID.
317 INT16
318 ASN1PushOID(
319 ASN1MarshalContext *ctx,
320 const BYTE *OID
321 )
322 {
323 if((*OID == ASN1_OBJECT_IDENTIFIER) && ((OID[1] & 0x80) == 0))
324 {
325 return ASN1PushBytes(ctx, OID[1] + 2, OID);
326 }
327 ctx->offset = -1;
328 return 0;
329 }
10.2.24 X509_ECC.c
10.2.24.1 Includes
1 #include "Tpm.h"
2 #include "X509.h"
3 #include "OIDs.h"
4 #include "TpmASN1_fp.h"
5 #include "X509_spt_fp.h"
6 #include "CryptHash_fp.h"
10.2.24.2 Functions
10.2.24.2.1 X509PushPoint()
7 INT16
8 X509PushPoint(
9 ASN1MarshalContext *ctx,
10 TPMS_ECC_POINT *p
11 )
12 {
13 // Push a bit string containing the public key. For now, push the x, and y
14 // coordinates of the public point, bottom up
15 ASN1StartMarshalContext(ctx); // BIT STRING
16 {
17 ASN1PushBytes(ctx, p->y.t.size, p->y.t.buffer);
18 ASN1PushBytes(ctx, p->x.t.size, p->x.t.buffer);
19 ASN1PushByte(ctx, 0x04);
20 }
21 return ASN1EndEncapsulation(ctx, ASN1_BITSTRING); // Ends BIT STRING
22 }
10.2.24.2.2 X509AddSigningAlgorithmECC()
23 INT16
24 X509AddSigningAlgorithmECC(
25 OBJECT *signKey,
26 TPMT_SIG_SCHEME *scheme,
27 ASN1MarshalContext *ctx
28 )
29 {
30 PHASH_DEF hashDef = CryptGetHashDef(scheme->details.any.hashAlg);
31 //
32 NOT_REFERENCED(signKey);
10.2.24.2.3 X509AddPublicECC()
This function will add the publicKey description to the DER data. If ctx is NULL, then no data is
transferred and this function will indicate if the TPM has the values for DER-encoding of the public key.
55 INT16
56 X509AddPublicECC(
57 OBJECT *object,
58 ASN1MarshalContext *ctx
59 )
60 {
61 const BYTE *curveOid =
62 CryptEccGetOID(object->publicArea.parameters.eccDetail.curveID);
63 if((curveOid == NULL) || (*curveOid != ASN1_OBJECT_IDENTIFIER))
64 return 0;
65 //
66 //
67 // SEQUENCE (2 elem) 1st
68 // SEQUENCE (2 elem) 2nd
69 // OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
70 // OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named curve)
71 // BIT STRING (520 bit) 000001001010000111010101010111001001101101000100000010...
72 //
73 // If this is a check to see if the key can be encoded, it can.
74 // Need to mark the end sequence
75 if(ctx == NULL)
76 return 1;
77 ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 1st
78 {
79 X509PushPoint(ctx, &object->publicArea.unique.ecc); // BIT STRING
80 ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 2nd
81 {
82 ASN1PushOID(ctx, curveOid); // curve dependent
83 ASN1PushOID(ctx, OID_ECC_PUBLIC); // (1.2.840.10045.2.1)
84 }
10.2.25 X509_RSA.c
10.2.25.1 Includes
1 #include "Tpm.h"
2 #include "X509.h"
3 #include "TpmASN1_fp.h"
4 #include "X509_spt_fp.h"
5 #include "CryptHash_fp.h"
6 #include "CryptRsa_fp.h"
10.2.25.2 Functions
7 #if ALG_RSA
10.2.25.2.1 X509AddSigningAlgorithmRSA()
8 INT16
9 X509AddSigningAlgorithmRSA(
10 OBJECT *signKey,
11 TPMT_SIG_SCHEME *scheme,
12 ASN1MarshalContext *ctx
13 )
14 {
15 TPM_ALG_ID hashAlg = scheme->details.any.hashAlg;
16 PHASH_DEF hashDef = CryptGetHashDef(hashAlg);
17 //
18 NOT_REFERENCED(signKey);
19 // return failure if hash isn't implemented
20 if(hashDef->hashAlg != hashAlg)
21 return 0;
22 switch(scheme->scheme)
23 {
24 case ALG_RSASSA_VALUE:
25 {
26 // if the hash is implemented but there is no PKCS1 OID defined
27 // then this is not a valid signing combination.
28 if(hashDef->PKCS1[0] != ASN1_OBJECT_IDENTIFIER)
29 break;
30 if(ctx == NULL)
31 return 1;
32 return X509PushAlgorithmIdentifierSequence(ctx, hashDef->PKCS1);
33 }
34 case ALG_RSAPSS_VALUE:
35 // leave if this is just an implementation check
36 if(ctx == NULL)
37 return 1;
38 // In the case of SHA1, everything is default and RFC4055 says that
39 // implementations that do signature generation MUST omit the parameter
40 // when defaults are used. )-:
41 if(hashDef->hashAlg == ALG_SHA1_VALUE)
42 {
43 return X509PushAlgorithmIdentifierSequence(ctx, OID_RSAPSS);
44 }
45 else
46 {
47 // Going to build something that looks like:
48 // SEQUENCE (2 elem)
49 // OBJECT IDENTIFIER 1.2.840.113549.1.1.10 rsaPSS (PKCS #1)
50 // SEQUENCE (3 elem)
51 // [0] (1 elem)
52 // SEQUENCE (2 elem)
53 // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256
54 // NULL
55 // [1] (1 elem)
56 // SEQUENCE (2 elem)
57 // OBJECT IDENTIFIER 1.2.840.113549.1.1.8 pkcs1-MGF
58 // SEQUENCE (2 elem)
59 // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256
60 // NULL
61 // [2] (1 elem) salt length
62 // INTEGER 32
63
64 // The indentation is just to keep track of where we are in the
65 // structure
66 ASN1StartMarshalContext(ctx); // SEQUENCE (2 elements)
67 {
68 ASN1StartMarshalContext(ctx); // SEQUENCE (3 elements)
69 {
70 // [2] (1 elem) salt length
71 // INTEGER 32
72 ASN1StartMarshalContext(ctx);
73 {
74 INT16 saltSize =
75 CryptRsaPssSaltSize((INT16)hashDef->digestSize,
76 (INT16)signKey->publicArea.unique.rsa.t.size);
77 ASN1PushUINT(ctx, saltSize);
78 }
79 ASN1EndEncapsulation(ctx, ASN1_APPLICAIION_SPECIFIC + 2);
80
81 // Add the mask generation algorithm
82 // [1] (1 elem)
83 // SEQUENCE (2 elem) 1st
84 // OBJECT IDENTIFIER 1.2.840.113549.1.1.8 pkcs1-MGF
85 // SEQUENCE (2 elem) 2nd
86 // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256
87 // NULL
88 ASN1StartMarshalContext(ctx); // mask context [1] (1 elem)
89 {
90 ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 1st
91 // Handle the 2nd Sequence (sequence (object, null))
92 {
93 // This adds a NULL, then an OID and a SEQUENCE
94 // wrapper.
95 X509PushAlgorithmIdentifierSequence(ctx,
96 hashDef->OID);
97 // add the pkcs1-MGF OID
98 ASN1PushOID(ctx, OID_MGF1);
99 }
100 // End outer sequence
101 ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
102 }
103 // End the [1]
104 ASN1EndEncapsulation(ctx, ASN1_APPLICAIION_SPECIFIC + 1);
105
106 // Add the hash algorithm
107 // [0] (1 elem)
108 // SEQUENCE (2 elem) (done by
109 // X509PushAlgorithmIdentifierSequence)
110 // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST)
111 // NULL
112 ASN1StartMarshalContext(ctx); // [0] (1 elem)
113 {
114 X509PushAlgorithmIdentifierSequence(ctx, hashDef->OID);
115 }
116 ASN1EndEncapsulation(ctx, (ASN1_APPLICAIION_SPECIFIC + 0));
117 }
118 // SEQUENCE (3 elements) end
119 ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
120
121 // RSA PSS OID
122 // OBJECT IDENTIFIER 1.2.840.113549.1.1.10 rsaPSS (PKCS #1)
123 ASN1PushOID(ctx, OID_RSAPSS);
124 }
125 // End Sequence (2 elements)
126 return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
127 }
128 default:
129 break;
130 }
131 return 0;
132 }
10.2.25.2.2 X509AddPublicRSA()
This function will add the publicKey description to the DER data. If fillPtr is NULL, then no data is
transferred and this function will indicate if the TPM has the values for DER-encoding of the public key.
133 INT16
134 X509AddPublicRSA(
135 OBJECT *object,
136 ASN1MarshalContext *ctx
137 )
138 {
139 UINT32 exp = object->publicArea.parameters.rsaDetail.exponent;
140 //
141 /*
142 SEQUENCE (2 elem) 1st
143 SEQUENCE (2 elem) 2nd
144 OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1)
145 NULL
146 BIT STRING (1 elem)
147 SEQUENCE (2 elem) 3rd
148 INTEGER (2048 bit) 2197304513741227955725834199357401
149 INTEGER 65537
150 */
151 // If this is a check to see if the key can be encoded, it can.
152 // Need to mark the end sequence
153 if(ctx == NULL)
154 return 1;
155 ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 1st
156 ASN1StartMarshalContext(ctx); // BIT STRING
157 ASN1StartMarshalContext(ctx); // SEQUENCE *(2 elem) 3rd
158
159 // Get public exponent in big-endian byte order.
160 if(exp == 0)
161 exp = RSA_DEFAULT_PUBLIC_EXPONENT;
162
163 // Push a 4 byte integer. This might get reduced if there are leading zeros or
164 // extended if the high order byte is negative.
165 ASN1PushUINT(ctx, exp);
166 // Push the public key as an integer
167 ASN1PushInteger(ctx, object->publicArea.unique.rsa.t.size,
168 object->publicArea.unique.rsa.t.buffer);
169 // Embed this in a SEQUENCE tag and length in for the key, exponent sequence
170 ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); // SEQUENCE (3rd)
171
172 // Embed this in a BIT STRING
173 ASN1EndEncapsulation(ctx, ASN1_BITSTRING);
174
175 // Now add the formatted SEQUENCE for the RSA public key OID. This is a
176 // fully constructed value so it doesn't need to have a context started
177 X509PushAlgorithmIdentifierSequence(ctx, OID_PKCS1_PUB);
178
179 return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
180 }
181 #endif // ALG_RSA
10.2.26 X509_spt.c
10.2.26.1 Includes
1 #include "Tpm.h"
2 #include "TpmASN1.h"
3 #include "TpmASN1_fp.h"
4 #define _X509_SPT_
5 #include "X509.h"
6 #include "X509_spt_fp.h"
7 #if ALG_RSA
8 # include "X509_RSA_fp.h"
9 #endif // ALG_RSA
10 #if ALG_ECC
11 # include "X509_ECC_fp.h"
12 #endif // ALG_ECC
13 #if ALG_SM2
14 //# include "X509_SM2_fp.h"
15 #endif // ALG_RSA
10.2.26.2.1 X509FindExtensionByOID()
This will search a list of X509 extensions to find an extension with the requested OID. If the extension is
found, the output context (ctx) is set up to point to the OID in the extension.
16 BOOL
17 X509FindExtensionByOID(
18 ASN1UnmarshalContext *ctxIn, // IN: the context to search
19 ASN1UnmarshalContext *ctx, // OUT: the extension context
20 const BYTE *OID // IN: oid to search for
21 )
22 {
23 INT16 length;
24 //
25 pAssert(ctxIn != NULL);
26 // Make the search non-destructive of the input if ctx provided. Otherwise, use
27 // the provided context.
28 if (ctx == NULL)
29 ctx = ctxIn;
30 // if the provide search context is different from the context of the extension,
31 // then copy the search context to the search context.
32 else if(ctx != ctxIn)
33 *ctx = *ctxIn;
34 // Now, search in the extension context
35 for(;ctx->size > ctx->offset; ctx->offset += length)
36 {
37 VERIFY((length = ASN1NextTag(ctx)) >= 0);
38 // If this is not a constructed sequence, then it doesn't belong
39 // in the extensions.
40 VERIFY(ctx->tag == ASN1_CONSTRUCTED_SEQUENCE);
41 // Make sure that this entry could hold the OID
42 if (length >= OID_SIZE(OID))
43 {
44 // See if this is a match for the provided object identifier.
10.2.26.2.2 X509GetExtensionBits()
This function will extract a bit field from an extension. If the extension doesn't contain a bit string, it will
fail.
63 UINT32
64 X509GetExtensionBits(
65 ASN1UnmarshalContext *ctx,
66 UINT32 *value
67 )
68 {
69 INT16 length;
70 //
71 while (((length = ASN1NextTag(ctx)) > 0) && (ctx->size > ctx->offset))
72 {
73 // Since this is an extension, the extension value will be in an OCTET STRING
74 if (ctx->tag == ASN1_OCTET_STRING)
75 {
76 return ASN1GetBitStringValue(ctx, value);
77 }
78 ctx->offset += length;
79 }
80 ctx->size = -1;
81 return FALSE;
82 }
10.2.26.2.3 X509ProcessExtensions()
This function is used to process the TPMA_OBJECT and KeyUsage() extensions. It is not in the
CertifyX509.c code because it makes the code harder to follow.
83 TPM_RC
84 X509ProcessExtensions(
85 OBJECT *object, // IN: The object with the attributes to
86 // check
87 stringRef *extension // IN: The start and length of the extensions
88 )
89 {
90 ASN1UnmarshalContext ctx;
91 ASN1UnmarshalContext extensionCtx;
92 INT16 length;
93 UINT32 value;
94 TPMA_OBJECT attributes = object->publicArea.objectAttributes;
95 //
96 if(!ASN1UnmarshalContextInitialize(&ctx, extension->len, extension->buf)
97 || ((length = ASN1NextTag(&ctx)) < 0)
98 || (ctx.tag != X509_EXTENSIONS))
99 return TPM_RCS_VALUE;
100 if( ((length = ASN1NextTag(&ctx)) < 0)
101 || (ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE)))
102 return TPM_RCS_VALUE;
103
104 // Get the extension for the TPMA_OBJECT if there is one
105 if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_TCG_TPMA_OBJECT) &&
106 X509GetExtensionBits(&extensionCtx, &value))
107 {
108 // If an keyAttributes extension was found, it must be exactly the same as the
109 // attributes of the object.
110 // NOTE: MemoryEqual() is used rather than a simple UINT32 compare to avoid
111 // type-punned pointer warning/error.
112 if(!MemoryEqual(&value, &attributes, sizeof(value)))
113 return TPM_RCS_ATTRIBUTES;
114 }
115 // Make sure the failure to find the value wasn't because of a fatal error
116 else if(extensionCtx.size < 0)
117 return TPM_RCS_VALUE;
118
119 // Get the keyUsage extension. This one is required
120 if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_KEY_USAGE_EXTENSION) &&
121 X509GetExtensionBits(&extensionCtx, &value))
122 {
123 x509KeyUsageUnion keyUsage;
124 BOOL bad;
125 //
126 keyUsage.integer = value;
127 // For KeyUsage:
128 // 1) 'sign' is SET if Key Usage includes signing
129 bad = (KEY_USAGE_SIGN.integer & keyUsage.integer) != 0
130 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign);
131 // 2) 'decrypt' is SET if Key Usage includes decryption uses
132 bad = bad || (KEY_USAGE_DECRYPT.integer & keyUsage.integer) != 0
133 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt);
134 // 3) 'fixedTPM' is SET if Key Usage is non-repudiation
135 bad = bad || IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE, nonrepudiation)
136 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM);
137 // 4)'restricted' is SET if Key Usage is for key agreement.
138 bad = bad || IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE, keyAgreement)
139 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted);
140 if(bad)
141 return TPM_RCS_VALUE;
142 }
143 else
144 // The KeyUsage extension is required
145 return TPM_RCS_VALUE;
146
147 return TPM_RC_SUCCESS;
148 }
10.2.26.3.1 X509AddSigningAlgorithm()
149 INT16
150 X509AddSigningAlgorithm(
151 ASN1MarshalContext *ctx,
152 OBJECT *signKey,
153 TPMT_SIG_SCHEME *scheme
154 )
155 {
156 switch(signKey->publicArea.type)
157 {
158 #if ALG_RSA
159 case ALG_RSA_VALUE:
160 return X509AddSigningAlgorithmRSA(signKey, scheme, ctx);
161 #endif // ALG_RSA
162 #if ALG_ECC
163 case ALG_ECC_VALUE:
164 return X509AddSigningAlgorithmECC(signKey, scheme, ctx);
165 #endif // ALG_ECC
166 #if ALG_SM2
167 case ALG_SM2:
168 return X509AddSigningAlgorithmSM2(signKey, scheme,ctx);
169 #endif // ALG_SM2
170 default:
171 break;
172 }
173 return 0;
174 }
10.2.26.3.2 X509AddPublicKey()
This function will add the publicKey description to the DER data. If fillPtr is NULL, then no data is
transferred and this function will indicate if the TPM has the values for DER-encoding of the public key.
175 INT16
176 X509AddPublicKey(
177 ASN1MarshalContext *ctx,
178 OBJECT *object
179 )
180 {
181 switch(object->publicArea.type)
182 {
183 #if ALG_RSA
184 case ALG_RSA_VALUE:
185 return X509AddPublicRSA(object, ctx);
186 #endif
187 #if ALG_ECC
188 case ALG_ECC_VALUE:
189 return X509AddPublicECC(object, ctx);
190 #endif
191 #if ALG_SM2
192 case ALG_SM2_VALUE:
193 break;
194 #endif
195 default:
196 break;
197 }
198 return FALSE;
199 }
10.2.26.3.3 X509PushAlgorithmIdentifierSequence()
200 INT16
201 X509PushAlgorithmIdentifierSequence(
202 ASN1MarshalContext *ctx,
203 const BYTE *OID
204 )
205 {
206 ASN1StartMarshalContext(ctx); // hash algorithm
207 ASN1PushNull(ctx);
208 ASN1PushOID(ctx, OID);
209 return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
210 }
10.2.27 AC_spt.c
10.2.27.1 Includes
1 #include "Tpm.h"
2 #include "AC_spt_fp.h"
3 #if 1 // This is the simulated AC data.
4 typedef struct {
5 TPMI_RH_AC ac;
6 TPML_AC_CAPABILITIES *acData;
7
8 } acCapabilities;
9 TPML_AC_CAPABILITIES acData0001 = {1,
10 {{TPM_AT_PV1, 0x01234567}}};
11
12 acCapabilities ac[1] = { {0x0001, &acData0001} };
13
14 #define NUM_AC (sizeof(ac) / sizeof(acCapabilities))
15 #endif // 1 The simulated AC data
10.2.27.1.1 AcToCapabilities()
16 TPML_AC_CAPABILITIES *
17 AcToCapabilities(
18 TPMI_RH_AC component // IN: component
19 )
20 {
21 UINT32 index;
22 //
23 for(index = 0; index < NUM_AC; index++)
24 {
25 if(ac[index].ac == component)
26 return ac[index].acData;
27 }
28 return NULL;
29 }
10.2.27.1.2 AcIsAccessible()
30 BOOL
31 AcIsAccessible(
32 TPM_HANDLE acHandle
33 )
34 {
35 // In this implementation, the AC exists if there are some capabilities to go
36 // with the handle
37 return AcToCapabilities(acHandle) != NULL;
38 }
10.2.27.1.3 AcCapabilitiesGet()
39 TPMI_YES_NO
40 AcCapabilitiesGet(
41 TPMI_RH_AC component, // IN: the component
42 TPM_AT type, // IN: start capability type
43 TPML_AC_CAPABILITIES *capabilityList // OUT: list of handle
44 )
45 {
46 TPMI_YES_NO more = NO;
47 UINT32 i;
48 TPML_AC_CAPABILITIES *capabilities = AcToCapabilities(component);
49
50 pAssert(HandleGetType(component) == TPM_HT_AC);
51
52 // Initialize output handle list
53 capabilityList->count = 0;
54
55 if(capabilities != NULL)
56 {
57 // Find the first capability less than or equal to type
58 for(i = 0; i < capabilities->count; i++)
59 {
60 if(capabilities->acCapabilities[i].tag >= type)
61 {
62 // copy the capabilities until we run out or fill the list
63 for(; (capabilityList->count < MAX_AC_CAPABILITIES)
64 && (i < capabilities->count); i++)
65 {
66 capabilityList->acCapabilities[capabilityList->count]
67 = capabilities->acCapabilities[i];
68 capabilityList->count++;
69 }
70 more = i < capabilities->count;
71 }
72 }
73 }
74 return more;
75 }
10.2.27.1.4 AcSendObject()
76 TPM_RC
77 AcSendObject(
78 TPM_HANDLE acHandle, // IN: Handle of AC receiving object
79 OBJECT *object, // IN: object structure to send
80 TPMS_AC_OUTPUT *acDataOut // OUT: results of operation
81 )
82 {
83 NOT_REFERENCED(object);
84 NOT_REFERENCED(acHandle);
85 acDataOut->tag = TPM_AT_ERROR; // indicate that the response contains an
86 // error code
87 acDataOut->data = TPM_AE_NONE; // but there is no error.
88
89 return TPM_RC_SUCCESS;
90 }
Annex A
(informative)
Implementation Dependent
A.1 Introduction
This header file contains definitions that are used to define a TPM profile. The values are chosen by the
manufacturer. The values here are chosen to represent a full featured TPM so that all of the TPM’s
capabilities can be simulated and tested. This file would change based on the implementation.
The file listed below was generated by an automated tool using three documents as inputs. They are:
The TCG_Algorithm Registery,
Part 2 of this specification, and
A purpose-built document that contains vendor-specific information in tables.
All of the values in this file have #ifdef ‘guards’ so that they may be defined in a command
line.Additionally, TpmBuildSwitches.h allows an additional file to be specified in the compiler command
line and preset any of these values.
A.2 TpmProfile.h
1 #ifndef _TPM_PROFILE_H_
2 #define _TPM_PROFILE_H_
3 #undef TRUE
4 #define TRUE 1
5 #undef FALSE
6 #define FALSE 0
7 #undef YES
8 #define YES 1
9 #undef NO
10 #define NO 0
11 #undef SET
12 #define SET 1
13 #undef CLEAR
14 #define CLEAR 0
15 #ifndef BIG_ENDIAN_TPM
16 #define BIG_ENDIAN_TPM NO
17 #endif
18 #ifndef LITTLE_ENDIAN_TPM
19 #define LITTLE_ENDIAN_TPM !BIG_ENDIAN_TPM
20 #endif
21 #ifndef MOST_SIGNIFICANT_BIT_0
22 #define MOST_SIGNIFICANT_BIT_0 NO
23 #endif
24 #ifndef LEAST_SIGNIFICANT_BIT_0
25 #define LEAST_SIGNIFICANT_BIT_0 !MOST_SIGNIFICANT_BIT_0
26 #endif
27 #ifndef AUTO_ALIGN
28 #define AUTO_ALIGN NO
29 #endif
30 #ifndef ECC_NIST_P192
31 #define ECC_NIST_P192 NO
32 #endif
33 #ifndef ECC_NIST_P224
34 #define ECC_NIST_P224 NO
35 #endif
36 #ifndef ECC_NIST_P256
37 #define ECC_NIST_P256 YES
38 #endif
39 #ifndef ECC_NIST_P384
40 #define ECC_NIST_P384 YES
41 #endif
42 #ifndef ECC_NIST_P521
43 #define ECC_NIST_P521 NO
44 #endif
45 #ifndef ECC_BN_P256
46 #define ECC_BN_P256 YES
47 #endif
48 #ifndef ECC_BN_P638
49 #define ECC_BN_P638 NO
50 #endif
51 #ifndef ECC_SM2_P256
52 #define ECC_SM2_P256 NO
53 #endif
54 #ifndef RH_ACT_0
55 #define RH_ACT_0 YES
56 #endif
57 #ifndef RH_ACT_1
58 #define RH_ACT_1 NO
59 #endif
60 #ifndef RH_ACT_A
61 #define RH_ACT_A YES
62 #endif
63 #ifndef FIELD_UPGRADE_IMPLEMENTED
64 #define FIELD_UPGRADE_IMPLEMENTED NO
65 #endif
66 #ifndef HASH_LIB
67 #define HASH_LIB Ossl
68 #endif
69 #ifndef SYM_LIB
70 #define SYM_LIB Ossl
71 #endif
72 #ifndef MATH_LIB
73 #define MATH_LIB Ossl
74 #endif
75 #ifndef IMPLEMENTATION_PCR
76 #define IMPLEMENTATION_PCR 24
77 #endif
78 #ifndef PLATFORM_PCR
79 #define PLATFORM_PCR 24
80 #endif
81 #ifndef DRTM_PCR
82 #define DRTM_PCR 17
83 #endif
84 #ifndef HCRTM_PCR
85 #define HCRTM_PCR 0
86 #endif
87 #ifndef NUM_LOCALITIES
88 #define NUM_LOCALITIES 5
89 #endif
90 #ifndef MAX_HANDLE_NUM
91 #define MAX_HANDLE_NUM 3
92 #endif
93 #ifndef MAX_ACTIVE_SESSIONS
94 #define MAX_ACTIVE_SESSIONS 64
95 #endif
96 #ifndef CONTEXT_SLOT
97 #define CONTEXT_SLOT UINT16
98 #endif
99 #ifndef MAX_LOADED_SESSIONS
100 #define MAX_LOADED_SESSIONS 3
101 #endif
102 #ifndef MAX_SESSION_NUM
103 #define MAX_SESSION_NUM 3
104 #endif
105 #ifndef MAX_LOADED_OBJECTS
106 #define MAX_LOADED_OBJECTS 3
107 #endif
108 #ifndef MIN_EVICT_OBJECTS
109 #define MIN_EVICT_OBJECTS 2
110 #endif
111 #ifndef NUM_POLICY_PCR_GROUP
112 #define NUM_POLICY_PCR_GROUP 1
113 #endif
114 #ifndef NUM_AUTHVALUE_PCR_GROUP
115 #define NUM_AUTHVALUE_PCR_GROUP 1
116 #endif
117 #ifndef MAX_CONTEXT_SIZE
118 #define MAX_CONTEXT_SIZE 1264
119 #endif
120 #ifndef MAX_DIGEST_BUFFER
121 #define MAX_DIGEST_BUFFER 1024
122 #endif
123 #ifndef MAX_NV_INDEX_SIZE
124 #define MAX_NV_INDEX_SIZE 2048
125 #endif
126 #ifndef MAX_NV_BUFFER_SIZE
127 #define MAX_NV_BUFFER_SIZE 1024
128 #endif
129 #ifndef MAX_CAP_BUFFER
130 #define MAX_CAP_BUFFER 1024
131 #endif
132 #ifndef NV_MEMORY_SIZE
133 #define NV_MEMORY_SIZE 16384
134 #endif
135 #ifndef MIN_COUNTER_INDICES
136 #define MIN_COUNTER_INDICES 8
137 #endif
138 #ifndef NUM_STATIC_PCR
139 #define NUM_STATIC_PCR 16
140 #endif
141 #ifndef MAX_ALG_LIST_SIZE
142 #define MAX_ALG_LIST_SIZE 64
143 #endif
144 #ifndef PRIMARY_SEED_SIZE
145 #define PRIMARY_SEED_SIZE 32
146 #endif
147 #ifndef CONTEXT_ENCRYPT_ALGORITHM
148 #define CONTEXT_ENCRYPT_ALGORITHM AES
149 #endif
150 #ifndef NV_CLOCK_UPDATE_INTERVAL
151 #define NV_CLOCK_UPDATE_INTERVAL 12
152 #endif
153 #ifndef NUM_POLICY_PCR
154 #define NUM_POLICY_PCR 1
155 #endif
156 #ifndef MAX_COMMAND_SIZE
157 #define MAX_COMMAND_SIZE 4096
158 #endif
159 #ifndef MAX_RESPONSE_SIZE
160 #define MAX_RESPONSE_SIZE 4096
161 #endif
162 #ifndef ORDERLY_BITS
163 #define ORDERLY_BITS 8
164 #endif
165 #ifndef MAX_SYM_DATA
166 #define MAX_SYM_DATA 128
167 #endif
168 #ifndef MAX_RNG_ENTROPY_SIZE
169 #define MAX_RNG_ENTROPY_SIZE 64
170 #endif
171 #ifndef RAM_INDEX_SPACE
172 #define RAM_INDEX_SPACE 512
173 #endif
174 #ifndef RSA_DEFAULT_PUBLIC_EXPONENT
175 #define RSA_DEFAULT_PUBLIC_EXPONENT 0x00010001
176 #endif
177 #ifndef ENABLE_PCR_NO_INCREMENT
178 #define ENABLE_PCR_NO_INCREMENT YES
179 #endif
180 #ifndef CRT_FORMAT_RSA
181 #define CRT_FORMAT_RSA YES
182 #endif
183 #ifndef VENDOR_COMMAND_COUNT
184 #define VENDOR_COMMAND_COUNT 0
185 #endif
186 #ifndef MAX_VENDOR_BUFFER_SIZE
187 #define MAX_VENDOR_BUFFER_SIZE 1024
188 #endif
189 #ifndef MAX_DERIVATION_BITS
190 #define MAX_DERIVATION_BITS 8192
191 #endif
192 #ifndef SIZE_OF_X509_SERIAL_NUMBER
193 #define SIZE_OF_X509_SERIAL_NUMBER 20
194 #endif
195 #ifndef PRIVATE_VENDOR_SPECIFIC_BYTES
196 #define PRIVATE_VENDOR_SPECIFIC_BYTES RSA_PRIVATE_SIZE
197 #endif
338 #endif
A.3 TpmSizeChecks.c
1 #include "Tpm.h"
2 #include <stdio.h>
3 #include <assert.h>
4 #if RUNTIME_SIZE_CHECKS
5 #if TABLE_DRIVEN_MARSHAL
6 extern uint32_t MarshalDataSize;
7 #endif
8
9 static int once = 0;
10
11 //** TpmSizeChecks()
12 // This function is used during the development process to make sure that the
13 // vendor-specific values result in a consistent implementation. When possible,
14 // the code contains #if to do compile-time checks. However, in some cases, the
15 // values require the use of "sizeof()" and that can't be used in an #if.
16 BOOL
17 TpmSizeChecks(
18 void
19 )
20 {
21 BOOL PASS = TRUE;
22 #if DEBUG
23 //
24 if(once++ != 0)
25 return 1;
26 {
27 UINT32 maxAsymSecurityStrength = MAX_ASYM_SECURITY_STRENGTH;
28 UINT32 maxHashSecurityStrength = MAX_HASH_SECURITY_STRENGTH;
29 UINT32 maxSymSecurityStrength = MAX_SYM_SECURITY_STRENGTH;
30 UINT32 maxSecurityStrengthBits = MAX_SECURITY_STRENGTH_BITS;
31 UINT32 proofSize = PROOF_SIZE;
32 UINT32 compliantProofSize = COMPLIANT_PROOF_SIZE;
33 UINT32 compliantPrimarySeedSize = COMPLIANT_PRIMARY_SEED_SIZE;
34 UINT32 primarySeedSize = PRIMARY_SEED_SIZE;
35
36 UINT32 cmacState = sizeof(tpmCmacState_t);
37 UINT32 hashState = sizeof(HASH_STATE);
38 UINT32 keyScheduleSize = sizeof(tpmCryptKeySchedule_t);
39 //
40 NOT_REFERENCED(cmacState);
41 NOT_REFERENCED(hashState);
42 NOT_REFERENCED(keyScheduleSize);
43 NOT_REFERENCED(maxAsymSecurityStrength);
44 NOT_REFERENCED(maxHashSecurityStrength);
45 NOT_REFERENCED(maxSymSecurityStrength);
46 NOT_REFERENCED(maxSecurityStrengthBits);
47 NOT_REFERENCED(proofSize);
48 NOT_REFERENCED(compliantProofSize);
49 NOT_REFERENCED(compliantPrimarySeedSize);
50 NOT_REFERENCED(primarySeedSize);
51
52 {
53 TPMT_SENSITIVE *p;
54 // This assignment keeps compiler from complaining about a conditional
55 // comparison being between two constants
56 UINT16 max_rsa_key_bytes = MAX_RSA_KEY_BYTES;
57 if((max_rsa_key_bytes / 2) != (sizeof(p->sensitive.rsa.t.buffer) / 5))
58 {
59 printf("Sensitive part of TPMT_SENSITIVE is undersized. May be caused"
60 " by use of wrong version of Part 2.\n");
61 PASS = FALSE;
62 }
63 }
64 #if TABLE_DRIVEN_MARSHAL
65 printf("sizeof(MarshalData) = %zu\n", sizeof(MarshalData_st));
66 #endif
67
133 {
134 uint32_t act;
135 for(act = 0; act < 16; act++)
136 {
137 switch(act)
138 {
139 FOR_EACH_ACT(CASE_ACT_NUMBER)
140 if(!_plat__ACT_GetImplemented(act))
141 {
142 printf("TPM_RH_ACT_%1X is not implemented by platform\n",
143 act);
144 PASS = FALSE;
145 }
146 default:
147 break;
148 }
149 }
150 }
151 #endif // DEBUG
152 return (PASS);
153 }
154 #endif // RUNTIME_SIZE_CHECKS
Annex B
(informative)
Library-Specific
B.1 Introduction
This clause contains the files that are specific to a cryptographic library used by the TPM code.
Three categories are defined for cryptographic functions:
big number math (asymmetric cryptography),
symmetric ciphers, and
hash functions.
The code is structured to make it possible to use different libraries for different categories. For example,
one might choose to use OpenSSL for its math library, but use a different library for hashing and
symmetric cryptography. Since OpenSSL supports all three categories, it might be more typical to
combine libraries of specific functions; that is, one library might only contain block ciphers while another
supports big number math.
B.2.1. Introduction
The following files are specific to a port that uses the OpenSSL library for cryptographic functions.
B.2.2.1. TpmToOsslHash.h
B.2.2.1.1. Introduction
This header file is used to splice the OpenSSL hash code into the TPM code.
1 #ifndef HASH_LIB_DEFINED
2 #define HASH_LIB_DEFINED
3 #define HASH_LIB_OSSL
4 #include <openssl/evp.h>
5 #include <openssl/sha.h>
6 #include <openssl/sm3.h>
7 #include <openssl/ossl_typ.h>
Redefine the internal name used for each of the hash state structures to the name used by the library.
These defines need to be known in all parts of the TPM so that the structure sizes can be properly
computed when needed.
The defines below are only needed when compiling CryptHash.c or CryptSmac.c. This isolation is
primarily to avoid name space collision. However, if there is a real collision, it will likely show up when the
linker tries to put things together.
13 #ifdef _CRYPT_HASH_C_
14 typedef BYTE *PBYTE;
15 typedef const BYTE *PCBYTE;
Define the interface between CryptHash.c to the functions provided by the library. For each method,
define the calling parameters of the method and then define how the method is invoked in CryptHash.c.
All hashes are required to have the same calling sequence. If they don't, create a simple adaptation
function that converts from the standard form of the call to the form used by the specific hash (and then
send a nasty letter to the person who wrote the hash function for the library).
The macro that calls the method also defines how the parameters get swizzled between the default form
(in CryptHash.c)and the library form.
20 #define HASH_DATA_METHOD_DEF \
21 void (HASH_DATA_METHOD)(PANY_HASH_STATE state, \
22 PCBYTE buffer, \
23 size_t size)
24 #define HASH_DATA(hashState, dInSize, dIn) \
25 ((hashState)->def->method.data)(&(hashState)->state, dIn, dInSize)
26 #define HASH_END_METHOD_DEF \
27 void (HASH_END_METHOD)(BYTE *buffer, PANY_HASH_STATE state)
28 #define HASH_END(hashState, buffer) \
29 ((hashState)->def->method.end)(buffer, &(hashState)->state)
NOTE: For import, export, and copy, memcpy() is used since there is no reformatting necessary between the internal
and external forms.
30 #define HASH_STATE_COPY_METHOD_DEF \
31 void (HASH_STATE_COPY_METHOD)(PANY_HASH_STATE to, \
32 PCANY_HASH_STATE from, \
33 size_t size)
34 #define HASH_STATE_COPY(hashStateOut, hashStateIn) \
35 ((hashStateIn)->def->method.copy)(&(hashStateOut)->state, \
36 &(hashStateIn)->state, \
37 (hashStateIn)->def->contextSize)
Copy (with reformatting when necessary) an internal hash structure to an external blob
38 #define HASH_STATE_EXPORT_METHOD_DEF \
39 void (HASH_STATE_EXPORT_METHOD)(BYTE *to, \
40 PCANY_HASH_STATE from, \
41 size_t size)
42 #define HASH_STATE_EXPORT(to, hashStateFrom) \
43 ((hashStateFrom)->def->method.copyOut) \
44 (&(((BYTE *)(to))[offsetof(HASH_STATE, state)]), \
45 &(hashStateFrom)->state, \
46 (hashStateFrom)->def->contextSize)
Copy from an external blob to an internal formate (with reformatting when necessary
47 #define HASH_STATE_IMPORT_METHOD_DEF \
48 void (HASH_STATE_IMPORT_METHOD)(PANY_HASH_STATE to, \
49 const BYTE *from, \
50 size_t size)
51 #define HASH_STATE_IMPORT(hashStateTo, from) \
52 ((hashStateTo)->def->method.copyIn) \
53 (&(hashStateTo)->state, \
54 &(((const BYTE *)(from))[offsetof(HASH_STATE, state)]),\
55 (hashStateTo)->def->contextSize)
Function aliases. The code in CryptHash.c uses the internal designation for the functions. These need to
be translated to the function names of the library.
89 #define HashLibSimulationEnd()
90 #endif // HASH_LIB_DEFINED
B.2.2.2. TpmToOsslMath.h
B.2.2.2.1. Introduction
This file contains the structure definitions used for ECC in the LibTomCrypt() version of the code. These
definitions would change, based on the library. The ECC-related structures that cross the TPM interface
are defined in TpmTypes.h
1 #ifndef MATH_LIB_DEFINED
2 #define MATH_LIB_DEFINED
3 #define MATH_LIB_OSSL
4 #include <openssl/evp.h>
5 #include <openssl/ec.h>
6 #if OPENSSL_VERSION_NUMBER >= 0x10200000L
7 // Check the bignum_st definition in crypto/bn/bn_lcl.h and either update the
8 // version check or provide the new definition for this version.
9 # error Untested OpenSSL version
10 #elif OPENSSL_VERSION_NUMBER >= 0x10100000L
11 // from crypto/bn/bn_lcl.h
12 struct bignum_st {
13 BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit
14 * chunks. */
15 int top; /* Index of last used d +1. */
16 /* The next are internal book keeping for
bn_expand. */
17 int dmax; /* Size of the d array. */
18 int neg; /* one if the number is negative */
19 int flags;
20 };
21 #endif // OPENSSL_VERSION_NUMBER
22 #include <openssl/bn.h>
Make sure that the library is using the correct size for a crypt word
Allocate a local BIGNUM value. For the allocation, a bigNum structure is created as is a local BIGNUM.
The bigNum is initialized and then the BIGNUM is set to reference the local value.
41 BN_CTX *CTX; // the context for the math (this might not be
42 // the context in which the curve was created>;
43 } OSSL_CURVE_DATA;
44 typedef OSSL_CURVE_DATA *bigCurve;
45 #define AccessCurveData(E) ((E)->C)
46 #include "TpmToOsslSupport_fp.h"
Start and end a context within which the OpenSSL memory management works
Start and end a context that spans multiple ECC functions. This is used so that the group for the curve
can persist across multiple frames.
Start and end a local stack frame within the context of the curve frame
56 #define MathLibSimulationEnd()
57 #endif // MATH_LIB_DEFINED
B.2.2.3. TpmToOsslSym.h
B.2.2.3.1. Introduction
This header file is used to splice the OpenSSL library into the TPM code.
The support required of a library are a hash module, a block cipher module and portions of a big number
library. All of the library-dependent headers should have the same guard to that only the first one gets
defined.
1 #ifndef SYM_LIB_DEFINED
2 #define SYM_LIB_DEFINED
3 #define SYM_LIB_OSSL
4 #include <openssl/aes.h>
5 #include <openssl/des.h>
6 #include <openssl/sm4.h>
7 #include <openssl/camellia.h>
8 #include <openssl/bn.h>
9 #include <openssl/ossl_typ.h>
The Crypt functions that call the block encryption function use the parameters in the order:
keySchedule
in buffer
out buffer Since open SSL uses the order in encryptoCall_t above, need to swizzle the values to the
order required by the library.
Define the order of parameters to the library functions that do block encryption and decryption.
12 typedef void(*TpmCryptSetSymKeyCall_t)(
13 const BYTE *in,
14 BYTE *out,
15 void *keySchedule
16 );
17 #define SYM_ALIGNMENT RADIX_BYTES
Macros to alias encryption calls to specific algorithms. This should be used sparingly. Currently, only used
by CryptSym.c and CryptRand.c
When using these calls, to call the AES block encryption code, the caller should use:
TpmCryptEncryptAES(SWIZZLE(keySchedule, in, out));
25 #if ALG_TDES
26 #include "TpmToOsslDesSupport_fp.h"
27 #endif
28 #define TpmCryptSetEncryptKeyTDES(key, keySizeInBits, schedule) \
29 TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule))
30 #define TpmCryptSetDecryptKeyTDES(key, keySizeInBits, schedule) \
31 TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule))
Macros to alias encryption calls to specific algorithms. This should be used sparingly. Currently, only used
by CryptRand.c
Macros to alias encryption calls to specific algorithms. This should be used sparingly.
Macros to alias encryption calls to specific algorithms. This should be used sparingly.
Forward reference
50 #define SymLibSimulationEnd()
51 #endif // SYM_LIB_DEFINED
B.2.3.1. TpmToOsslDesSupport.c
B.2.3.1.1. Introduction
The functions in this file are used for initialization of the interface to the OpenSSL library.
1 #include "Tpm.h"
2 #if (defined SYM_LIB_OSSL) && ALG_TDES
B.2.3.1.3. Functions
B.2.3.1.3.1. TDES_set_encyrpt_key()
This function makes creation of a TDES key look like the creation of a key for any of the other OpenSSL
block ciphers. It will create three key schedules, one for each of the DES keys. If there are only two keys,
then the third schedule is a copy of the first.
3 void
4 TDES_set_encrypt_key(
5 const BYTE *key,
6 UINT16 keySizeInBits,
7 tpmKeyScheduleTDES *keySchedule
8 )
9 {
10 DES_set_key_unchecked((const_DES_cblock *)key, &keySchedule[0]);
11 DES_set_key_unchecked((const_DES_cblock *)&key[8], &keySchedule[1]);
12 // If is two-key, copy the schedule for K1 into K3, otherwise, compute the
13 // the schedule for K3
14 if(keySizeInBits == 128)
15 keySchedule[2] = keySchedule[0];
16 else
17 DES_set_key_unchecked((const_DES_cblock *)&key[16],
18 &keySchedule[2]);
19 }
B.2.3.1.3.2. TDES_encyrpt()
The TPM code uses one key schedule. For TDES, the schedule contains three schedules. OpenSSL
wants the schedules referenced separately. This function does that.
20 void TDES_encrypt(
21 const BYTE *in,
22 BYTE *out,
23 tpmKeyScheduleTDES *ks
24 )
25 {
26 DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out,
27 &ks[0], &ks[1], &ks[2],
28 DES_ENCRYPT);
29 }
B.2.3.1.3.3. TDES_decrypt()
As with TDES_encypt() this function bridges between the TPM single schedule model and the OpenSSL
three schedule model.
30 void TDES_decrypt(
31 const BYTE *in,
32 BYTE *out,
33 tpmKeyScheduleTDES *ks
34 )
35 {
36 DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out,
37 &ks[0], &ks[1], &ks[2],
38 DES_DECRYPT);
39 }
40 #endif // SYM_LIB_OSSL
B.2.3.2. TpmToOsslMath.c
B.2.3.2.1. Introduction
The functions in this file provide the low-level interface between the TPM code and the big number and
elliptic curve math routines in OpenSSL.
Most math on big numbers require a context. The context contains the memory in which OpenSSL
creates and manages the big number values. When a OpenSSL math function will be called that modifies
a BIGNUM value, that value must be created in an OpenSSL context. The first line of code in such a
function must be: OSSL_ENTER(); and the last operation before returning must be OSSL_LEAVE().
OpenSSL variables can then be created with BnNewVariable(). Constant values to be used by OpenSSL
are created from the bigNum values passed to the functions in this file. Space for the BIGNUM control
block is allocated in the stack of the function and then it is initialized by calling BigInitialized(). That
function sets up the values in the BIGNUM structure and sets the data pointer to point to the data in the
bignum_t. This is only used when the value is known to be a constant in the called function.
Because the allocations of constants is on the local stack and the OSSL_ENTER()/OSSL_LEAVE() pair
flushes everything created in OpenSSL memory, there should be no chance of a memory leak.
1 #include "Tpm.h"
2 #ifdef MATH_LIB_OSSL
3 #include "TpmToOsslMath_fp.h"
B.2.3.2.3. Functions
B.2.3.2.3.1. OsslToTpmBn()
This function converts an OpenSSL BIGNUM to a TPM bignum. In this implementation it is assumed that
OpenSSL uses a different control structure but the same data layout -- an array of native-endian words in
little-endian order.
4 BOOL
5 OsslToTpmBn(
6 bigNum bn,
7 BIGNUM *osslBn
8 )
9 {
10 VERIFY(osslBn != NULL);
11 // If the bn is NULL, it means that an output value pointer was NULL meaning that
12 // the results is simply to be discarded.
13 if(bn != NULL)
14 {
15 int i;
16 //
17 VERIFY((unsigned)osslBn->top <= BnGetAllocated(bn));
18 for(i = 0; i < osslBn->top; i++)
19 bn->d[i] = osslBn->d[i];
20 BnSetTop(bn, osslBn->top);
21 }
22 return TRUE;
23 Error:
24 return FALSE;
25 }
B.2.3.2.3.2. BigInitialized()
This function initializes an OSSL BIGNUM from a TPM bigConst. Do not use this for values that are
passed to OpenSLL when they are not declared as const in the function prototype. Instead, use
BnNewVariable().
26 BIGNUM *
27 BigInitialized(
28 BIGNUM *toInit,
29 bigConst initializer
30 )
31 {
32 if(initializer == NULL)
33 FAIL(FATAL_ERROR_PARAMETER);
34 if(toInit == NULL || initializer == NULL)
35 return NULL;
36 toInit->d = (BN_ULONG *)&initializer->d[0];
37 toInit->dmax = (int)initializer->allocated;
38 toInit->top = (int)initializer->size;
39 toInit->neg = 0;
40 toInit->flags = 0;
41 return toInit;
42 }
43 #ifndef OSSL_DEBUG
44 # define BIGNUM_PRINT(label, bn, eol)
45 # define DEBUG_PRINT(x)
46 #else
47 # define DEBUG_PRINT(x) printf("%s", x)
48 # define BIGNUM_PRINT(label, bn, eol) BIGNUM_print((label), (bn), (eol))
B.2.3.2.3.3. BIGNUM_print()
49 static void
50 BIGNUM_print(
51 const char *label,
52 const BIGNUM *a,
53 BOOL eol
54 )
55 {
56 BN_ULONG *d;
57 int i;
58 int notZero = FALSE;
59
60 if(label != NULL)
61 printf("%s", label);
62 if(a == NULL)
63 {
64 printf("NULL");
65 goto done;
66 }
67 if (a->neg)
68 printf("-");
69 for(i = a->top, d = &a->d[i - 1]; i > 0; i--)
70 {
71 int j;
72 BN_ULONG l = *d--;
73 for(j = BN_BITS2 - 8; j >= 0; j -= 8)
74 {
75 BYTE b = (BYTE)((l >> j) & 0xFF);
B.2.3.2.3.4. BnNewVariable()
This function allocates a new variable in the provided context. If the context does not exist or the
allocation fails, it is a catastrophic failure.
89 static BIGNUM *
90 BnNewVariable(
91 BN_CTX *CTX
92 )
93 {
94 BIGNUM *new;
95 //
96 // This check is intended to protect against calling this function without
97 // having initialized the CTX.
98 if((CTX == NULL) || ((new = BN_CTX_get(CTX)) == NULL))
99 FAIL(FATAL_ERROR_ALLOCATION);
100 return new;
101 }
102 #if LIBRARY_COMPATIBILITY_CHECK
B.2.3.2.3.5. MathLibraryCompatibilityCheck()
103 BOOL
104 MathLibraryCompatibilityCheck(
105 void
106 )
107 {
108 OSSL_ENTER();
109 BIGNUM *osslTemp = BnNewVariable(CTX);
110 crypt_uword_t i;
111 BYTE test[] = {0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
112 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
113 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
114 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
115 BN_VAR(tpmTemp, sizeof(test) * 8); // allocate some space for a test value
116 //
117 // Convert the test data to a bigNum
118 BnFromBytes(tpmTemp, test, sizeof(test));
119 // Convert the test data to an OpenSSL BIGNUM
120 BN_bin2bn(test, sizeof(test), osslTemp);
121 // Make sure the values are consistent
122 VERIFY(osslTemp->top == (int)tpmTemp->size);
123 for(i = 0; i < tpmTemp->size; i++)
124 VERIFY(osslTemp->d[i] == tpmTemp->d[i]);
125 OSSL_LEAVE();
126 return 1;
127 Error:
128 return 0;
129 }
130 #endif
B.2.3.2.3.6. BnModMult()
This function does a modular multiply. It first does a multiply and then a divide and returns the remainder
of the divide.
B.2.3.2.3.7. BnMult()
B.2.3.2.3.8. BnDiv()
This function divides two bigNum values. The function returns FALSE if there is an error in the operation.
B.2.3.2.3.9. BnGcd()
B.2.3.2.3.10. BnModExp()
Do modular exponentiation using bigNum values. The conversion from a bignum_t to a bigNum is trivial
as they are based on the same structure
B.2.3.2.3.11. BnModInverse()
B.2.3.2.3.12. PointFromOssl()
301 if(OK)
302 {
303 OsslToTpmBn(pOut->x, x);
304 OsslToTpmBn(pOut->y, y);
305 BnSetWord(pOut->z, 1);
306 }
307 else
308 BnSetWord(pOut->z, 0);
309 BN_CTX_end(E->CTX);
310 return OK;
311 }
B.2.3.2.3.13. EcPointInitialized()
B.2.3.2.3.14. BnCurveInitialize()
This function initializes the OpenSSL curve information structure. This structure points to the TPM-defined
values for the curve, to the context for the number values in the frame, and to the OpenSSL-defined
group values.
B.2.3.2.3.15. BnCurveFree()
This function will free the allocated components of the curve and end the frame in which the curve data
exists
B.2.3.2.3.16. BnEccModMult()
B.2.3.2.3.17. BnEccModMult2()
B.2.3.2.4. BnEccAdd()
B.2.3.3. TpmToOsslSupport.c
B.2.3.3.1. Introduction
The functions in this file are used for initialization of the interface to the OpenSSL library.
1 #include "Tpm.h"
2 #if defined(HASH_LIB_OSSL) || defined(MATH_LIB_OSSL) || defined(SYM_LIB_OSSL)
B.2.3.3.2.1. SupportLibInit()
4 LIB_EXPORT int
5 SupportLibInit(
6 void
7 )
8 {
9 return TRUE;
10 }
B.2.3.3.2.2. OsslContextEnter()
This function is used to initialize an OpenSSL context at the start of a function that will call to an
OpenSSL math function.
11 BN_CTX *
12 OsslContextEnter(
13 void
14 )
15 {
16 BN_CTX *CTX = BN_CTX_new();
17 //
18 return OsslPushContext(CTX);
19 }
B.2.3.3.2.3. OsslContextLeave()
20 void
21 OsslContextLeave(
22 BN_CTX *CTX
23 )
24 {
25 OsslPopContext(CTX);
26 BN_CTX_free(CTX);
27 }
B.2.3.3.2.4. OsslPushContext()
This function is used to create a frame in a context. All values allocated within this context after the frame
is started will be automatically freed when the context (OsslPopContext()
28 BN_CTX *
29 OsslPushContext(
30 BN_CTX *CTX
31 )
32 {
33 if(CTX == NULL)
34 FAIL(FATAL_ERROR_ALLOCATION);
35 BN_CTX_start(CTX);
36 return CTX;
37 }
B.2.3.3.2.5. OsslPopContext()
38 void
39 OsslPopContext(
40 BN_CTX *CTX
41 )
42 {
43 // BN_CTX_end can't be called with NULL. It will blow up.
44 if(CTX != NULL)
45 BN_CTX_end(CTX);
46 }
47 #endif // HASH_LIB_OSSL || MATH_LIB_OSSL || SYM_LIB_OSSL
Annex C
(informative)
Simulation Environment
C.1 Introduction
These files are used to simulate some of the implementation-dependent hardware of a TPM. These files
are provided to allow creation of a simulation environment for the TPM. These files are not expected to be
part of a hardware TPM implementation.
C.2 Cancel.c
C.2.1. Description
1 #include "Platform.h"
C.2.3. Functions
C.2.3.1. _plat__IsCanceled()
2 LIB_EXPORT int
3 _plat__IsCanceled(
4 void
5 )
6 {
7 // return cancel flag
8 return s_isCanceled;
9 }
C.2.3.2. _plat__SetCancel()
10 LIB_EXPORT void
11 _plat__SetCancel(
12 void
13 )
14 {
15 s_isCanceled = TRUE;
16 return;
17 }
C.2.3.3. _plat__ClearCancel()
18 LIB_EXPORT void
19 _plat__ClearCancel(
20 void
21 )
22 {
23 s_isCanceled = FALSE;
24 return;
25 }
C.3 Clock.c
C.3.1. Description
This file contains the routines that are used by the simulator to mimic a hardware clock on a TPM.
In this implementation, all the time values are measured in millisecond. However, the precision of the
clock functions may be implementation dependent.
1 #include <assert.h>
2 #include "Platform.h"
3 #include "TpmFail_fp.h"
C.3.3.1. Introduction
This set of functions is intended to be called by the simulator environment in order to simulate hardware
events.
C.3.3.2. _plat__TimerReset()
This function sets current system clock time as t0 for counting TPM time. This function is called at a
power on event to reset the clock. When the clock is reset, the indication that the clock was stopped is
also set.
4 LIB_EXPORT void
5 _plat__TimerReset(
6 void
7 )
8 {
9 s_lastSystemTime = 0;
10 s_tpmTime = 0;
11 s_adjustRate = CLOCK_NOMINAL;
12 s_timerReset = TRUE;
13 s_timerStopped = TRUE;
14 return;
15 }
C.3.3.3. _plat__TimerRestart()
This function should be called in order to simulate the restart of the timer should it be stopped while
power is still applied.
16 LIB_EXPORT void
17 _plat__TimerRestart(
18 void
19 )
20 {
21 s_timerStopped = TRUE;
22 return;
23 }
C.3.4.1. Introduction
These functions are called by the TPM code. They should be replaced by appropriated hardware
functions.
24 #include <time.h>
25 clock_t debugTime;
26
27 //*** _plat__RealTime()
28 // This is another, probably futile, attempt to define a portable function
29 // that will return a 64-bit clock value that has mSec resolution.
30 LIB_EXPORT uint64_t
31 _plat__RealTime(
32 void
33 )
34 {
35 clock64_t time;
36 #ifdef _MSC_VER
37 struct _timeb sysTime;
38 //
39 _ftime_s(&sysTime);
40 time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm;
41 // set the time back by one hour if daylight savings
42 if(sysTime.dstflag)
43 time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour
44 #else
45 // hopefully, this will work with most UNIX systems
46 struct timespec systime;
47 //
48 clock_gettime(CLOCK_MONOTONIC, &systime);
49 time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000);
50 #endif
51 return time;
52 }
C.3.4.2. _plat__TimerRead()
This function provides access to the tick timer of the platform. The TPM code uses this value to drive the
TPM Clock.
The tick timer is supposed to run when power is applied to the device. This timer should not be reset by
time events including _TPM_Init(). It should only be reset when TPM power is re-applied.
If the TPM is run in a protected environment, that environment may provide the tick time to the TPM as
long as the time provided by the environment is not allowed to go backwards. If the time provided by the
system can go backwards during a power discontinuity, then the _plat__Signal_PowerOn() should call
_plat__TimerReset().
53 LIB_EXPORT uint64_t
54 _plat__TimerRead(
55 void
56 )
57 {
58 #ifdef HARDWARE_CLOCK
59 #error "need a defintion for reading the hardware clock"
60 return HARDWARE_CLOCK
61 #else
62 clock64_t timeDiff;
63 clock64_t adjustedTimeDiff;
64 clock64_t timeNow;
65 clock64_t readjustedTimeDiff;
66
67 // This produces a timeNow that is basically locked to the system clock.
68 timeNow = _plat__RealTime();
69
70 // if this hasn't been initialized, initialize it
71 if(s_lastSystemTime == 0)
72 {
73 s_lastSystemTime = timeNow;
74 debugTime = clock();
75 s_lastReportedTime = 0;
76 s_realTimePrevious = 0;
77 }
78 // The system time can bounce around and that's OK as long as we don't allow
79 // time to go backwards. When the time does appear to go backwards, set
80 // lastSystemTime to be the new value and then update the reported time.
81 if(timeNow < s_lastReportedTime)
82 s_lastSystemTime = timeNow;
83 s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime;
84 s_lastSystemTime = timeNow;
85 timeNow = s_lastReportedTime;
86
87 // The code above produces a timeNow that is similar to the value returned
88 // by Clock(). The difference is that timeNow does not max out, and it is
89 // at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below
90 // uses that value and does the rate adjustment on the time value.
91 // If there is no difference in time, then skip all the computations
92 if(s_realTimePrevious >= timeNow)
93 return s_tpmTime;
94 // Compute the amount of time since the last update of the system clock
95 timeDiff = timeNow - s_realTimePrevious;
96
97 // Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec
98 adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate);
99
100 // update the TPM time with the adjusted timeDiff
101 s_tpmTime += (clock64_t)adjustedTimeDiff;
102
103 // Might have some rounding error that would loose CLOCKS. See what is not
104 // being used. As mentioned above, this could result in putting back more than
105 // is taken out. Here, we are trying to recreate timeDiff.
106 readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate )
107 / CLOCK_NOMINAL;
108
109 // adjusted is now converted back to being the amount we should advance the
110 // previous sampled time. It should always be less than or equal to timeDiff.
111 // That is, we could not have use more time than we started with.
112 s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff;
113
114 #ifdef DEBUGGING_TIME
115 // Put this in so that TPM time will pass much faster than real time when
116 // doing debug.
117 // A value of 1000 for DEBUG_TIME_MULTIPLER will make each ms into a second
118 // A good value might be 100
119 return (s_tpmTime * DEBUG_TIME_MULTIPLIER);
120 #endif
121 return s_tpmTime;
122 #endif
123 }
C.3.4.3. _plat__TimerWasReset()
This function is used to interrogate the flag indicating if the tick timer has been reset.
If the resetFlag parameter is SET, then the flag will be CLEAR before the function returns.
C.3.4.4. _plat__TimerWasStopped()
This function is used to interrogate the flag indicating if the tick timer has been stopped. If so, this is
typically a reason to roll the nonce.
This function will CLEAR the s_timerStopped flag before returning. This provides functionality that is
similar to status register that is cleared when read. This is the model used here because it is the one that
has the most impact on the TPM code as the flag can only be accessed by one entity in the TPM. Any
other implementation of the hardware can be made to look like a read-once register.
C.3.4.5. _plat__ClockAdjustRate()
170 default:
171 // ignore any other values;
172 break;
173 }
174
175 if(s_adjustRate > (CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT))
176 s_adjustRate = CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT;
177 if(s_adjustRate < (CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT))
178 s_adjustRate = CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT;
179
180 return;
181 }
C.4 Entropy.c
1 #define _CRT_RAND_S
2 #include <stdlib.h>
3 #include <memory.h>
4 #include <time.h>
5 #include "Platform.h"
6 #ifdef _MSC_VER
7 #include <process.h>
8 #else
9 #include <unistd.h>
10 #endif
This is the last 32-bits of hardware entropy produced. We have to check to see that two consecutive 32-
bit values are not the same because (according to FIPS 140-2, annex C
"If each call to a RNG produces blocks of n bits (where n > 15), the first n-bit block generated after power-
up, initialization, or reset shall not be used, but shall be saved for comparison with the next n-bit block to
be generated. Each subsequent generation of an n-bit block shall be compared with the previously
generated block. The test shall fail if any two compared n-bit blocks are equal."
C.4.1.1. _plat__GetEntropy()
This function is used to get available hardware entropy. In a hardware implementation of this function,
there would be no call to the system to get entropy.
38 LIB_EXPORT int32_t
39 _plat__GetEntropy(
40 unsigned char *entropy, // output buffer
41 uint32_t amount // amount requested
42 )
43 {
44 uint32_t rndNum;
45 int32_t ret;
46 //
47 if(amount == 0)
48 {
49 // Seed the platform entropy source if the entropy source is software. There
50 // is no reason to put a guard macro (#if or #ifdef) around this code because
51 // this code would not be here if someone was changing it for a system with
52 // actual hardware.
53 //
54 // NOTE 1: The following command does not provide proper cryptographic
55 // entropy. Its primary purpose to make sure that different instances of the
56 // simulator, possibly started by a script on the same machine, are seeded
57 // differently. Vendors of the actual TPMs need to ensure availability of
58 // proper entropy using their platform-specific means.
59 //
60 // NOTE 2: In debug builds by default the reference implementation will seed
61 // its RNG deterministically (without using any platform provided randomness).
62 // See the USE_DEBUG_RNG macro and DRBG_GetEntropy() function.
63 #ifdef _MSC_VER
64 srand((unsigned)_plat__RealTime() ^ _getpid());
65 #else
66 srand((unsigned)_plat__RealTime() ^ getpid());
67 #endif
68 lastEntropy = rand32();
69 ret = 0;
70 }
71 else
72 {
73 rndNum = rand32();
74 if(rndNum == lastEntropy)
75 {
76 ret = -1;
77 }
78 else
79 {
80 lastEntropy = rndNum;
81 // Each process will have its random number generator initialized
82 // according to the process id and the initialization time. This is not a
83 // lot of entropy so, to add a bit more, XOR the current time value into
84 // the returned entropy value.
85 // NOTE: the reason for including the time here rather than have it in
86 // in the value assigned to lastEntropy is that rand() could be broken and
87 // using the time would in the lastEntropy value would hide this.
88 rndNum ^= (uint32_t)_plat__RealTime();
89
90 // Only provide entropy 32 bits at a time to test the ability
91 // of the caller to deal with partial results.
92 ret = MIN(amount, sizeof(rndNum));
93 memcpy(entropy, &rndNum, ret);
94 }
95 }
96 return ret;
97 }
C.5 LocalityPlat.c
C.5.1. Includes
1 #include "Platform.h"
C.5.2. Functions
C.5.2.1. _plat__LocalityGet()
Get the most recent command locality in locality value form. This is an integer value for locality and not a
locality structure The locality can be 0-4 or 32-255. 5-31 is not allowed.
C.5.2.2. _plat__LocalitySet()
9 LIB_EXPORT void
10 _plat__LocalitySet(
11 unsigned char locality
12 )
13 {
14 if(locality > 4 && locality < 32)
15 locality = 0;
16 s_locality = locality;
17 return;
18 }
C.6 NVMem.c
C.6.1. Description
This file contains the NV read and write access methods. This implementation uses RAM/file and does
not manage the RAM/file as NV blocks. The implementation may become more sophisticated over time.
1 #include <memory.h>
2 #include <string.h>
3 #include <assert.h>
4 #include "Platform.h"
5 #if FILE_BACKED_NV
6 # include <stdio.h>
7 FILE *s_NvFile = NULL;
8 int s_NeedsManufacture = FALSE;
9 #endif
10
11 //**Functions
12
13 #if FILE_BACKED_NV
14
15 //*** NvFileOpen()
16 // This function opens the file used to hold the NV image.
17 // Return Type: int
18 // >= 0 success
19 // -1 error
20 static int
21 NvFileOpen(
22 const char *mode
23 )
24 {
25 #if defined(NV_FILE_PATH)
26 # define TO_STRING(s) TO_STRING_IMPL(s)
27 # define TO_STRING_IMPL(s) #s
28 const char* s_NvFilePath = TO_STRING(NV_FILE_PATH);
29 # undef TO_STRING
30 # undef TO_STRING_IMPL
31 #else
32 const char* s_NvFilePath = "NVChip";
33 #endif
34
35 // Try to open an exist NVChip file for read/write
36 # if defined _MSC_VER && 1
37 if(fopen_s(&s_NvFile, s_NvFilePath, mode) != 0)
38 s_NvFile = NULL;
39 # else
40 s_NvFile = fopen(s_NvFilePath, mode);
41 # endif
42 return (s_NvFile == NULL) ? -1 : 0;
43 }
C.6.2.1. NvFileCommit()
44 static int
45 NvFileCommit(
46 void
47 )
48 {
49 int OK;
50 // If NV file is not available, return failure
51 if(s_NvFile == NULL)
52 return 1;
53 // Write RAM data to NV
54 fseek(s_NvFile, 0, SEEK_SET);
55 OK = (NV_MEMORY_SIZE == fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NvFile));
56 OK = OK && (0 == fflush(s_NvFile));
57 assert(OK);
58 return OK;
59 }
C.6.2.2. NvFileSize()
This function gets the size of the NV file and puts the file pointer were desired using the seek method
values. SEEK_SET => beginning; SEEK_CUR => current position and SEEK_END => to the end of the
file.
60 static long
61 NvFileSize(
62 int leaveAt
63 )
64 {
65 long fileSize;
66 long filePos = ftell(s_NvFile);
67 //
68 assert(NULL != s_NvFile);
69
70 fseek(s_NvFile, 0, SEEK_END);
71 fileSize = ftell(s_NvFile);
72 switch(leaveAt)
73 {
74 case SEEK_SET:
75 filePos = 0;
76 case SEEK_CUR:
77 fseek(s_NvFile, filePos, SEEK_SET);
78 break;
79 case SEEK_END:
80 break;
81 default:
82 assert(FALSE);
83 break;
84 }
85 return fileSize;
86 }
87 #endif
C.6.2.3. _plat__NvErrors()
This function is used by the simulator to set the error flags in the NV subsystem to simulate an error in the
NV loading process
88 LIB_EXPORT void
89 _plat__NvErrors(
90 int recoverable,
91 int unrecoverable
92 )
93 {
94 s_NV_unrecoverable = unrecoverable;
95 s_NV_recoverable = recoverable;
96 }
C.6.2.4. _plat__NVEnable()
Enable NV memory.
This version just pulls in data from a file. In a real TPM, with NV on chip, this function would verify the
integrity of the saved context. If the NV memory was not on chip but was in something like RPMB, the NV
state would be read in, decrypted and integrity checked.
The recovery from an integrity failure depends on where the error occurred. It it was in the state that is
discarded by TPM Reset, then the error is recoverable if the TPM is reset. Otherwise, the TPM must go
into failure mode.
97 LIB_EXPORT int
98 _plat__NVEnable(
99 void *platParameter // IN: platform specific parameters
100 )
101 {
102 NOT_REFERENCED(platParameter); // to keep compiler quiet
103 //
104 // Start assuming everything is OK
105 s_NV_unrecoverable = FALSE;
106 s_NV_recoverable = FALSE;
107 #if FILE_BACKED_NV
108 if(s_NvFile != NULL)
109 return 0;
110 // Initialize all the bytes in the ram copy of the NV
111 _plat__NvMemoryClear(0, NV_MEMORY_SIZE);
112
113 // If the file exists
114 if(NvFileOpen("r+b") >= 0)
115 {
116 long fileSize = NvFileSize(SEEK_SET); // get the file size and leave the
117 // file pointer at the start
118 //
119 // If the size is right, read the data
120 if (NV_MEMORY_SIZE == fileSize)
121 {
122 s_NeedsManufacture =
123 fread(s_NV, 1, NV_MEMORY_SIZE, s_NvFile) != NV_MEMORY_SIZE;
124 }
125 else
126 {
127 NvFileCommit(); // for any other size, initialize it
128 s_NeedsManufacture = TRUE;
129 }
130 }
131 // If NVChip file does not exist, try to create it for read/write.
132 else if(NvFileOpen("w+b") >= 0)
133 {
134 NvFileCommit(); // Initialize the file
135 s_NeedsManufacture = TRUE;
136 }
137 assert(NULL != s_NvFile); // Just in case we are broken for some reason.
138 #endif
139 // NV contents have been initialized and the error checks have been performed. For
140 // simulation purposes, use the signaling interface to indicate if an error is
141 // to be simulated and the type of the error.
142 if(s_NV_unrecoverable)
143 return -1;
144 return s_NV_recoverable;
145 }
C.6.2.5. _plat__NVDisable()
Disable NV memory
C.6.2.6. _plat__IsNvAvailable()
Check if NV is available
C.6.2.7. _plat__NvMemoryRead()
C.6.2.8. _plat__NvIsDifferent()
This function checks to see if the NV is different from the test value. This is so that NV will not be written if
it has not changed.
C.6.2.9. _plat__NvMemoryWrite()
This function is used to update NV memory. The write is to a memory copy of NV. At the end of the
current command, any changes are written to the actual NV memory.
NOTE: A useful optimization would be for this code to compare the current contents of NV with the local copy and note
the blocks that have changed. Then only write those blocks when _plat__NvCommit() is called.
211 )
212 {
213 if(startOffset + size <= NV_MEMORY_SIZE)
214 {
215 memcpy(&s_NV[startOffset], data, size); // Copy the data to the NV image
216 return TRUE;
217 }
218 return FALSE;
219 }
C.6.2.10. _plat__NvMemoryClear()
Function is used to set a range of NV memory bytes to an implementation-dependent value. The value
represents the erase state of the memory.
C.6.2.11. _plat__NvMemoryMove()
Function: Move a chunk of NV memory from source to destination This function should ensure that if
there overlap, the original data is copied before it is written
C.6.2.12. _plat__NvCommit()
This function writes the local copy of NV to NV for permanent store. It will write NV_MEMORY_SIZE
bytes to NV. If a file is use, the entire file is written.
C.6.2.13. _plat__SetNvAvail()
Set the current NV state to available. This function is for testing purpose only. It is not part of the platform
NV logic
C.6.2.14. _plat__ClearNvAvail()
Set the current NV state to unavailable. This function is for testing purpose only. It is not part of the
platform NV logic
C.6.2.15. _plat__NVNeedsManufacture()
This function is used by the simulator to determine when the TPM's NV state needs to be manufactured.
C.7 PowerPlat.c
1 #include "Platform.h"
2 #include "_TPM_Init_fp.h"
C.7.2. Functions
C.7.2.1. _plat__Signal_PowerOn()
3 LIB_EXPORT int
4 _plat__Signal_PowerOn(
5 void
6 )
7 {
8 // Reset the timer
9 _plat__TimerReset();
10
11 // Need to indicate that we lost power
12 s_powerLost = TRUE;
13
14 return 0;
15 }
C.7.2.2. _plat__WasPowerLost()
16 LIB_EXPORT int
17 _plat__WasPowerLost(
18 void
19 )
20 {
21 int retVal = s_powerLost;
22 s_powerLost = FALSE;
23 return retVal;
24 }
C.7.2.3. _plat_Signal_Reset()
25 LIB_EXPORT int
26 _plat__Signal_Reset(
27 void
28 )
29 {
30 // Initialize locality
31 s_locality = 0;
32
33 // Command cancel
34 s_isCanceled = FALSE;
35
36 _TPM_Init();
37
38 // if we are doing reset but did not have a power failure, then we should
39 // not need to reload NV ...
40
41 return 0;
42 }
C.7.2.4. _plat__Signal_PowerOff()
43 LIB_EXPORT void
44 _plat__Signal_PowerOff(
45 void
46 )
47 {
48 // Prepare NV memory for power off
49 _plat__NVDisable(0);
50
51 // Disable tick ACT tick processing
52 _plat__ACT_EnableTicks(FALSE);
53
54 return;
55 }
C.8 PlatformData.h
This file contains the instance data for the Platform module. It is collected in this file so that the state of
the module is easier to manage.
1 #ifndef _PLATFORM_DATA_H_
2 #define _PLATFORM_DATA_H_
3 #ifdef _PLATFORM_DATA_C_
4 #define EXTERN
5 #else
6 #define EXTERN extern
7 #endif
From Cancel.c Cancel flag. It is initialized as FALSE, which indicate the command is not being canceled
C.9 PlatformData.c
C.9.1. Description
This file will instance the TPM variables that are not stack allocated. The descriptions for these variables
are in Global.h for this project.
C.9.2. Includes
1 #define _PLATFORM_DATA_C_
2 #include "Platform.h"
C.10 PPPlat.c
C.10.1. Description
This module simulates the physical presence interface pins on the TPM.
C.10.2. Includes
1 #include "Platform.h"
C.10.3. Functions
C.10.3.1. _plat__PhysicalPresenceAsserted()
2 LIB_EXPORT int
3 _plat__PhysicalPresenceAsserted(
4 void
5 )
6 {
7 // Do not know how to check physical presence without real hardware.
8 // so always return TRUE;
9 return s_physicalPresence;
10 }
C.10.3.2. _plat__Signal_PhysicalPresenceOn()
11 LIB_EXPORT void
12 _plat__Signal_PhysicalPresenceOn(
13 void
14 )
15 {
16 s_physicalPresence = TRUE;
17 return;
18 }
C.10.3.3. _plat__Signal_PhysicalPresenceOff()
19 LIB_EXPORT void
20 _plat__Signal_PhysicalPresenceOff(
21 void
22 )
23 {
24 s_physicalPresence = FALSE;
25 return;
26 }
C.11 RunCommand.c
C.11.1. Introduction
This module provides the platform specific entry and fail processing. The _plat__RunCommand() function
is used to call to ExecuteCommand() in the TPM code. This function does whatever processing is
necessary to set up the platform in anticipation of the call to the TPM including settup for error
processing.
The _plat__Fail() function is called when there is a failure in the TPM. The TPM code will have set the
flag to indicate that the TPM is in failure mode. This call will then recursively call ExecuteCommand() in
order to build the failure mode response. When ExecuteCommand() returns to _plat__Fail(), the platform
will do some platform specif operation to return to the environment in which the TPM is executing. For a
simulator, setjmp/longjmp is used. For an OS, a system exit to the OS would be appropriate.
1 #include "Platform.h"
2 #include <setjmp.h>
3 #include "ExecCommand_fp.h"
4 jmp_buf s_jumpBuffer;
5
6 //** Functions
7
8 //***_plat__RunCommand()
9 // This version of RunCommand will set up a jum_buf and call ExecuteCommand(). If
10 // the command executes without failing, it will return and RunCommand will return.
11 // If there is a failure in the command, then _plat__Fail() is called and it will
12 // longjump back to RunCommand which will call ExecuteCommand again. However, this
13 // time, the TPM will be in failure mode so ExecuteCommand will simply build
14 // a failure response and return.
15 LIB_EXPORT void
16 _plat__RunCommand(
17 uint32_t requestSize, // IN: command buffer size
18 unsigned char *request, // IN: command buffer
19 uint32_t *responseSize, // IN/OUT: response buffer size
20 unsigned char **response // IN/OUT: response buffer
21 )
22 {
23 setjmp(s_jumpBuffer);
24 ExecuteCommand(requestSize, request, responseSize, response);
25 }
C.11.2.1. _plat__Fail()
C.12 Unique.c
C.12.1. Introduction
In some implementations of the TPM, the hardware can provide a secret value to the TPM. This secret
value is statistically unique to the instance of the TPM. Typical uses of this value are to provide
personalization to the random number generation and as a shared secret between the TPM and the
manufacturer.
C.12.2. Includes
1 #include "Platform.h"
2 const char notReallyUnique[] =
3 "This is not really a unique value. A real unique value should"
4 " be generated by the platform.";
5
6 //** _plat__GetUnique()
7 // This function is used to access the platform-specific unique value.
8 // This function places the unique value in the provided buffer ('b')
9 // and returns the number of bytes transferred. The function will not
10 // copy more data than 'bSize'.
11 // NOTE: If a platform unique value has unequal distribution of uniqueness
12 // and 'bSize' is smaller than the size of the unique value, the 'bSize'
13 // portion with the most uniqueness should be returned.
14 LIB_EXPORT uint32_t
15 _plat__GetUnique(
16 uint32_t which, // authorities (0) or details
17 uint32_t bSize, // size of the buffer
18 unsigned char *b // output buffer
19 )
20 {
21 const char *from = notReallyUnique;
22 uint32_t retVal = 0;
23
24 if(which == 0) // the authorities value
25 {
26 for(retVal = 0;
27 *from != 0 && retVal < bSize;
28 retVal++)
29 {
30 *b++ = *from++;
31 }
32 }
33 else
34 {
35 #define uSize sizeof(notReallyUnique)
36 b = &b[((bSize < uSize) ? bSize : uSize) - 1];
37 for(retVal = 0;
38 *from != 0 && retVal < bSize;
39 retVal++)
40 {
41 *b-- = *from++;
42 }
43 }
44 return retVal;
45 }
C.13 DebugHelpers.c
C.13.1. Description
This file contains the NV read and write access methods. This implementation uses RAM/file and does
not manage the RAM/file as NV blocks. The implementation may become more sophisticated over time.
1 #include <stdio.h>
2 #include <time.h>
3 #include "Platform.h"
4 #if CERTIFYX509_DEBUG
5 FILE *fDebug = NULL;
6 const char *debugFileName = "DebugFile.txt";
7
8 static FILE *
9 fileOpen(
10 const char *fn,
11 const char *mode
12 )
13 {
14 FILE *f;
15 # if defined _MSC_VER
16 if(fopen_s(&f, fn, mode) != 0)
17 f = NULL;
18 # else
19 f = fopen(fn, "w");
20 # endif
21 return f;
22 }
C.13.2.1. DebugFileOpen()
This function opens the file used to hold the debug data.
23 int
24 DebugFileOpen(
25 void
26 )
27 {
28 time_t t = time(NULL);
29 //
30 // Get current date and time.
31 # if defined _MSC_VER
32 char timeString[100];
33 ctime_s(timeString, (size_t)sizeof(timeString), &t);
34 # else
35 char *timeString;
36 timeString = ctime(&t);
37 # endif
38 // Try to open the debug file
39 fDebug = fileOpen(debugFileName, "w");
40 if(fDebug)
41 {
C.13.2.2. DebugFileClose()
48 void
49 DebugFileClose(
50 void
51 )
52 {
53 if(fDebug)
54 fclose(fDebug);
55 }
C.13.2.3. DebugDumpBuffer()
56 void
57 DebugDumpBuffer(
58 int size,
59 unsigned char *buf,
60 const char *identifier
61 )
62 {
63 int i;
64 //
65 FILE *f = fileOpen(debugFileName, "a");
66 if(!f)
67 return;
68 if(identifier)
69 fprintf(fDebug, "%s\n", identifier);
70 if(buf)
71 {
72 for(i = 0; i < size; i++)
73 {
74 if(((i % 16) == 0) && (i))
75 fprintf(fDebug, "\n");
76 fprintf(fDebug, " %02X", buf[i]);
77 }
78 if((size % 16) != 0)
79 fprintf(fDebug, "\n");
80 }
81 fclose(f);
82 }
83 #endif // CERTIFYX509_DEBUG
C.14 Platform.h
1 #ifndef _PLATFORM_H_
2 #define _PLATFORM_H_
3 #include "TpmBuildSwitches.h"
4 #include "BaseTypes.h"
5 #include "TPMB.h"
6 #include "MinMax.h"
7 #include "TpmProfile.h"
8 #include "PlatformACT.h"
9 #include "PlatformClock.h"
10 #include "PlatformData.h"
11 #include "Platform_fp.h"
12 #endif // _PLATFORM_H_
C.15 PlatformACT.h
This file contains the definitions for the ACT macros and data types used in the ACT implementation.
1 #ifndef _PLATFORM_ACT_H_
2 #define _PLATFORM_ACT_H_
3 typedef struct ACT_DATA
4 {
5 uint32_t remaining;
6 uint32_t newValue;
7 uint8_t signaled;
8 uint8_t pending;
9 uint8_t number;
10 } ACT_DATA, *P_ACT_DATA;
11 #if !(defined RH_ACT_0) || (RH_ACT_0 != YES)
12 # undef RH_ACT_0
13 # define RH_ACT_0 NO
14 # define IF_ACT_0_IMPLEMENTED(op)
15 #else
16 # define IF_ACT_0_IMPLEMENTED(op) op(0)
17 #endif
18 #if !(defined RH_ACT_1) || (RH_ACT_1 != YES)
19 # undef RH_ACT_1
20 # define RH_ACT_1 NO
21 # define IF_ACT_1_IMPLEMENTED(op)
22 #else
23 # define IF_ACT_1_IMPLEMENTED(op) op(1)
24 #endif
25 #if !(defined RH_ACT_2) || (RH_ACT_2 != YES)
26 # undef RH_ACT_2
27 # define RH_ACT_2 NO
28 # define IF_ACT_2_IMPLEMENTED(op)
29 #else
30 # define IF_ACT_2_IMPLEMENTED(op) op(2)
31 #endif
32 #if !(defined RH_ACT_3) || (RH_ACT_3 != YES)
33 # undef RH_ACT_3
34 # define RH_ACT_3 NO
35 # define IF_ACT_3_IMPLEMENTED(op)
36 #else
37 # define IF_ACT_3_IMPLEMENTED(op) op(3)
38 #endif
39 #if !(defined RH_ACT_4) || (RH_ACT_4 != YES)
40 # undef RH_ACT_4
41 # define RH_ACT_4 NO
42 # define IF_ACT_4_IMPLEMENTED(op)
43 #else
44 # define IF_ACT_4_IMPLEMENTED(op) op(4)
45 #endif
46 #if !(defined RH_ACT_5) || (RH_ACT_5 != YES)
47 # undef RH_ACT_5
48 # define RH_ACT_5 NO
49 # define IF_ACT_5_IMPLEMENTED(op)
50 #else
51 # define IF_ACT_5_IMPLEMENTED(op) op(5)
52 #endif
53 #if !(defined RH_ACT_6) || (RH_ACT_6 != YES)
54 # undef RH_ACT_6
55 # define RH_ACT_6 NO
56 # define IF_ACT_6_IMPLEMENTED(op)
57 #else
58 # define IF_ACT_6_IMPLEMENTED(op) op(6)
59 #endif
60 #if !(defined RH_ACT_7) || (RH_ACT_7 != YES)
61 # undef RH_ACT_7
62 # define RH_ACT_7 NO
63 # define IF_ACT_7_IMPLEMENTED(op)
64 #else
65 # define IF_ACT_7_IMPLEMENTED(op) op(7)
66 #endif
67 #if !(defined RH_ACT_8) || (RH_ACT_8 != YES)
68 # undef RH_ACT_8
69 # define RH_ACT_8 NO
70 # define IF_ACT_8_IMPLEMENTED(op)
71 #else
72 # define IF_ACT_8_IMPLEMENTED(op) op(8)
73 #endif
74 #if !(defined RH_ACT_9) || (RH_ACT_9 != YES)
75 # undef RH_ACT_9
76 # define RH_ACT_9 NO
77 # define IF_ACT_9_IMPLEMENTED(op)
78 #else
79 # define IF_ACT_9_IMPLEMENTED(op) op(9)
80 #endif
81 #if !(defined RH_ACT_A) || (RH_ACT_A != YES)
82 # undef RH_ACT_A
83 # define RH_ACT_A NO
84 # define IF_ACT_A_IMPLEMENTED(op)
85 #else
86 # define IF_ACT_A_IMPLEMENTED(op) op(A)
87 #endif
88 #if !(defined RH_ACT_B) || (RH_ACT_B != YES)
89 # undef RH_ACT_B
90 # define RH_ACT_B NO
91 # define IF_ACT_B_IMPLEMENTED(op)
92 #else
93 # define IF_ACT_B_IMPLEMENTED(op) op(B)
94 #endif
95 #if !(defined RH_ACT_C) || (RH_ACT_C != YES)
96 # undef RH_ACT_C
97 # define RH_ACT_C NO
98 # define IF_ACT_C_IMPLEMENTED(op)
99 #else
100 # define IF_ACT_C_IMPLEMENTED(op) op(C)
101 #endif
102 #if !(defined RH_ACT_D) || (RH_ACT_D != YES)
103 # undef RH_ACT_D
104 # define RH_ACT_D NO
105 # define IF_ACT_D_IMPLEMENTED(op)
106 #else
107 # define IF_ACT_D_IMPLEMENTED(op) op(D)
108 #endif
109 #if !(defined RH_ACT_E) || (RH_ACT_E != YES)
110 # undef RH_ACT_E
111 # define RH_ACT_E NO
112 # define IF_ACT_E_IMPLEMENTED(op)
113 #else
114 # define IF_ACT_E_IMPLEMENTED(op) op(E)
115 #endif
116 #if !(defined RH_ACT_F) || (RH_ACT_F != YES)
117 # undef RH_ACT_F
118 # define RH_ACT_F NO
119 # define IF_ACT_F_IMPLEMENTED(op)
120 #else
121 # define IF_ACT_F_IMPLEMENTED(op) op(F)
122 #endif
123 #define FOR_EACH_ACT(op) \
124 IF_ACT_0_IMPLEMENTED(op) \
125 IF_ACT_1_IMPLEMENTED(op) \
126 IF_ACT_2_IMPLEMENTED(op) \
127 IF_ACT_3_IMPLEMENTED(op) \
128 IF_ACT_4_IMPLEMENTED(op) \
129 IF_ACT_5_IMPLEMENTED(op) \
130 IF_ACT_6_IMPLEMENTED(op) \
131 IF_ACT_7_IMPLEMENTED(op) \
132 IF_ACT_8_IMPLEMENTED(op) \
133 IF_ACT_9_IMPLEMENTED(op) \
134 IF_ACT_A_IMPLEMENTED(op) \
135 IF_ACT_B_IMPLEMENTED(op) \
136 IF_ACT_C_IMPLEMENTED(op) \
137 IF_ACT_D_IMPLEMENTED(op) \
138 IF_ACT_E_IMPLEMENTED(op) \
139 IF_ACT_F_IMPLEMENTED(op)
140 #endif // _PLATFORM_ACT_H_
C.16 PlatformACT.c
C.16.1. Includes
1 #include "Platform.h"
C.16.2. Functions
C.16.2.1. ActSignal()
2 static void
3 ActSignal(
4 P_ACT_DATA actData,
5 int on
6 )
7 {
8 if(actData == NULL)
9 return;
10 // If this is to turn a signal on, don't do anything if it is already on. If this
11 // is to turn the signal off, do it anyway because this might be for
12 // initialization.
13 if(on && (actData->signaled == TRUE))
14 return;
15 actData->signaled = (uint8_t)on;
16
17 // If there is an action, then replace the "Do something" with the correct action.
18 // It should test 'on' to see if it is turning the signal on or off.
19 switch(actData->number)
20 {
21 #if RH_ACT_0
22 case 0: // Do something
23 return;
24 #endif
25 #if RH_ACT_1
26 case 1: // Do something
27 return;
28 #endif
29 #if RH_ACT_2
30 case 2: // Do something
31 return;
32 #endif
33 #if RH_ACT_3
34 case 3: // Do something
35 return;
36 #endif
37 #if RH_ACT_4
38 case 4: // Do something
39 return;
40 #endif
41 #if RH_ACT_5
42 case 5: // Do something
43 return;
44 #endif
45 #if RH_ACT_6
46 case 6: // Do something
47 return;
48 #endif
49 #if RH_ACT_7
50 case 7: // Do something
51 return;
52 #endif
53 #if RH_ACT_8
54 case 8: // Do something
55 return;
56 #endif
57 #if RH_ACT_9
58 case 9: // Do something
59 return;
60 #endif
61 #if RH_ACT_A
62 case 0xA: // Do something
63 return;
64 #endif
65 #if RH_ACT_B
66 case 0xB:
67 // Do something
68 return;
69 #endif
70 #if RH_ACT_C
71 case 0xC: // Do something
72 return;
73 #endif
74 #if RH_ACT_D
75 case 0xD: // Do something
76 return;
77 #endif
78 #if RH_ACT_E
79 case 0xE: // Do something
80 return;
81 #endif
82 #if RH_ACT_F
83 case 0xF: // Do something
84 return;
85 #endif
86 default:
87 return;
88 }
89 }
C.16.2.2. ActGetDataPointer()
90 static P_ACT_DATA
91 ActGetDataPointer(
92 uint32_t act
93 )
94 {
95
96 #define RETURN_ACT_POINTER(N) if(0x##N == act) return &ACT_##N;
97
98 FOR_EACH_ACT(RETURN_ACT_POINTER)
99
100 return (P_ACT_DATA)NULL;
101 }
C.16.2.3. _plat__ACT_GetImplemented()
This function tests to see if an ACT is implemented. It is a belt and suspenders function because the TPM
should not be calling to to manipulate an ACT that is not implemented. However, this could help the
simulator code which doesn't necessarily know if an ACT is implemented or not.
105 )
106 {
107 return (ActGetDataPointer(act) != NULL);
108 }
C.16.2.4. _plat__ACT_GetRemaining()
This function returns the remaining time. If an update is pending, newValue is returned. Otherwise, the
current counter value is returned. Note that since the timers keep running, the returned value can get
stale immediately. The actual count value will be no greater than the returned value.
C.16.2.5. _plat__ACT_GetSignaled()
C.16.2.6. _plat__ACT_SetSignaled()
C.16.2.7. _plat__ACT_GetPending()
149 //
150 if(actData == NULL)
151 return 0;
152 return (int )actData->pending;
153 }
C.16.2.8. _plat__ACT_UpdateCounter()
This function is used to write the newValue for the counter. If an update is pending, then no update
occurs and the function returns FALSE. If setSignaled is TRUE, then the ACT signaled state is SET and if
newValue is 0, nothing is posted.
C.16.2.9. _plat__ACT_EnableTicks()
This enables and disables the processing of the once-per-second ticks. This should be turned off (enable
= FALSE) by _TPM_Init() and turned on (enable = TRUE) by TPM2_Startup() after all the initializations
have completed.
C.16.2.10. ActDecrement()
If newValue is non-zero it is copied to remaining and then newValue is set to zero. Then remaining is
decremented by one if it is not already zero. If the value is decremented to zero, then the associated
event is signaled. If setting remaining causes it to be greater than 1, then the signal associated with the
ACT is turned off.
187 if(actData->pending)
188 {
189 // If this update will cause the count to go from non-zero to zero, set
190 // the newValue to 1 so that it will timeout when decremented below.
191 if((actData->newValue == 0) && (actData->remaining != 0))
192 actData->newValue = 1;
193 actData->remaining = actData->newValue;
194
195 // Update processed
196 actData->pending = 0;
197 }
198 // no update so countdown if the count is non-zero but not max
199 if((actData->remaining != 0) && (actData->remaining != UINT32_MAX))
200 {
201 // If this countdown causes the count to go to zero, then turn the signal for
202 // the ACT on.
203 if((actData->remaining -= 1) == 0)
204 ActSignal(actData, TRUE);
205 }
206 // If the current value of the counter is non-zero, then the signal should be
207 // off.
208 if(actData->signaled && (actData->remaining > 0))
209 ActSignal(actData, FALSE);
210 }
C.16.2.11. _plat__ACT_Tick()
This processes the once-per-second clock tick from the hardware. This is set up for the simulator to use
the control interface to send ticks to the TPM. These ticks do not have to be on a per second basis. They
can be as slow or as fast as desired so that the simulation can be tested.
C.16.2.12. ActZero()
237 }
C.16.2.13. _plat__ACT_Initialize()
C.17 PlatformClock.h
This file contains the instance data for the Platform module. It is collected in this file so that the state of
the module is easier to manage.
1 #ifndef _PLATFORM_CLOCK_H_
2 #define _PLATFORM_CLOCK_H_
3 #ifdef _MSC_VER
4 #include <sys/types.h>
5 #include <sys/timeb.h>
6 #else
7 #include <sys/time.h>
8 #include <time.h>
9 #endif
CLOCK_NOMINAL is the number of hardware ticks per mS. A value of 300000 means that the nominal
clock rate used to drive the hardware clock is 30 MHz. The adjustment rates are used to determine the
conversion of the hardware ticks to internal hardware clock value. In practice, we would expect that there
woudl be a hardware register will accumulated mS. It would be incremented by the output of a pre-scaler.
The pre-scaler would divide the ticks from the clock by some value that would compensate for the
difference between clock time and real time. The code in Clock does the emulation of this function.
12 #define CLOCK_ADJUST_MEDIUM 30
13 #define CLOCK_ADJUST_FINE 1
The clock tolerance is +/-15% (4500 counts) Allow some guard band (16.7%)
Annex D
(informative)
Remote Procedure Interface
D.1 Introduction
D.2 TpmTcpProtocol.h
D.2.1. Introduction
TPM commands are communicated as BYTE streams on a TCP connection. The TPM command protocol
is enveloped with the interface protocol described in this file. The command is indicated by a UINT32 with
one of the values below. Most commands take no parameters return no TPM errors. In these cases the
TPM interface protocol acknowledges that command processing is completed by returning a UINT32=0.
The command TPM_SIGNAL_HASH_DATA takes a UINT32-prepended variable length BYTE array and
the interface protocol acknowledges command completion with a UINT32=0. Most TPM commands are
enveloped using the TPM_SEND_COMMAND interface command. The parameters are as indicated
below. The interface layer also appends a UIN32=0 to the TPM response for regularity.
1 #ifndef TCP_TPM_PROTOCOL_H
2 #define TCP_TPM_PROTOCOL_H
3 #define TPM_SIGNAL_POWER_ON 1
4 #define TPM_SIGNAL_POWER_OFF 2
5 #define TPM_SIGNAL_PHYS_PRES_ON 3
6 #define TPM_SIGNAL_PHYS_PRES_OFF 4
7 #define TPM_SIGNAL_HASH_START 5
8 #define TPM_SIGNAL_HASH_DATA 6
9 // {UINT32 BufferSize, BYTE[BufferSize] Buffer}
10 #define TPM_SIGNAL_HASH_END 7
11 #define TPM_SEND_COMMAND 8
12 // {BYTE Locality, UINT32 InBufferSize, BYTE[InBufferSize] InBuffer} ->
13 // {UINT32 OutBufferSize, BYTE[OutBufferSize] OutBuffer}
14 #define TPM_SIGNAL_CANCEL_ON 9
15 #define TPM_SIGNAL_CANCEL_OFF 10
16 #define TPM_SIGNAL_NV_ON 11
17 #define TPM_SIGNAL_NV_OFF 12
18 #define TPM_SIGNAL_KEY_CACHE_ON 13
19 #define TPM_SIGNAL_KEY_CACHE_OFF 14
20 #define TPM_REMOTE_HANDSHAKE 15
21 #define TPM_SET_ALTERNATIVE_RESULT 16
22 #define TPM_SIGNAL_RESET 17
23 #define TPM_SIGNAL_RESTART 18
24 #define TPM_SESSION_END 20
25 #define TPM_STOP 21
26 #define TPM_GET_COMMAND_RESPONSE_SIZES 25
27 #define TPM_ACT_GET_SIGNALED 26
28 #define TPM_TEST_FAILURE_MODE 30
29 enum TpmEndPointInfo
30 {
31 tpmPlatformAvailable = 0x01,
32 tpmUsesTbs = 0x02,
33 tpmInRawMode = 0x04,
34 tpmSupportsPP = 0x08
35 };
36 #ifdef _MSC_VER
37 # pragma warning(push, 3)
38 #endif
Existing RPC interface type definitions retained so that the implementation can be re-used
D.3 TcpServer.c
D.3.1. Description
1 #include "TpmBuildSwitches.h"
2 #include <stdio.h>
3 #ifdef _MSC_VER
4 # pragma warning(push, 3)
5 # include <windows.h>
6 # include <winsock.h>
7 # pragma warning(pop)
8 typedef int socklen_t;
9 #elif defined(__unix__)
10 # include <string.h>
11 # include <unistd.h>
12 # include <errno.h>
13 # include <stdint.h>
14 # include <netinet/in.h>
15 # include <sys/socket.h>
16 # include <pthread.h>
17 # define ZeroMemory(ptr, sz) (memset((ptr), 0, (sz)))
18 # define closesocket(x) close(x)
19 # define INVALID_SOCKET (-1)
20 # define SOCKET_ERROR (-1)
21 # define WSAGetLastError() (errno)
22 # define INT_PTR intptr_t
23 typedef int SOCKET;
24 #else
25 # error "Unsupported platform."
26 #endif
27 #ifndef TRUE
28 # define TRUE 1
29 #endif
30 #ifndef FALSE
31 # define FALSE 0
32 #endif
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include "TpmTcpProtocol.h"
37 #include "Manufacture_fp.h"
38 #include "TpmProfile.h"
39 #include "Simulator_fp.h"
40 #include "Platform_fp.h"
41 typedef int BOOL;
52 uint32_t largestCommandSize;
53 uint32_t largestCommand;
54 uint32_t largestResponseSize;
55 uint32_t largestResponse;
56 } CommandResponseSizes = {0};
57
58 #endif // __IGNORE_STATE___
59
60 //** Functions
61
62 //*** CreateSocket()
63 // This function creates a socket listening on 'PortNumber'.
64 static int
65 CreateSocket(
66 int PortNumber,
67 SOCKET *listenSocket
68 )
69 {
70 struct sockaddr_in MyAddress;
71 int res;
72 //
73 // Initialize Winsock
74 #ifdef _MSC_VER
75 WSADATA wsaData;
76 res = WSAStartup(MAKEWORD(2, 2), &wsaData);
77 if(res != 0)
78 {
79 printf("WSAStartup failed with error: %d\n", res);
80 return -1;
81 }
82 #endif
83 // create listening socket
84 *listenSocket = socket(PF_INET, SOCK_STREAM, 0);
85 if(INVALID_SOCKET == *listenSocket)
86 {
87 printf("Cannot create server listen socket. Error is 0x%x\n",
88 WSAGetLastError());
89 return -1;
90 }
91 // bind the listening socket to the specified port
92 ZeroMemory(&MyAddress, sizeof(MyAddress));
93 MyAddress.sin_port = htons((short)PortNumber);
94 MyAddress.sin_family = AF_INET;
95
96 res = bind(*listenSocket, (struct sockaddr*) &MyAddress, sizeof(MyAddress));
97 if(res == SOCKET_ERROR)
98 {
99 printf("Bind error. Error is 0x%x\n", WSAGetLastError());
100 return -1;
101 }
102 // listen/wait for server connections
103 res = listen(*listenSocket, 3);
104 if(res == SOCKET_ERROR)
105 {
106 printf("Listen error. Error is 0x%x\n", WSAGetLastError());
107 return -1;
108 }
109 return 0;
110 }
D.3.2.1. PlatformServer()
111 BOOL
112 PlatformServer(
113 SOCKET s
114 )
115 {
116 BOOL OK = TRUE;
117 uint32_t Command;
118 //
119 for(;;)
120 {
121 OK = ReadBytes(s, (char*)&Command, 4);
122 // client disconnected (or other error). We stop processing this client
123 // and return to our caller who can stop the server or listen for another
124 // connection.
125 if(!OK)
126 return TRUE;
127 Command = ntohl(Command);
128 switch(Command)
129 {
130 case TPM_SIGNAL_POWER_ON:
131 _rpc__Signal_PowerOn(FALSE);
132 break;
133 case TPM_SIGNAL_POWER_OFF:
134 _rpc__Signal_PowerOff();
135 break;
136 case TPM_SIGNAL_RESET:
137 _rpc__Signal_PowerOn(TRUE);
138 break;
139 case TPM_SIGNAL_RESTART:
140 _rpc__Signal_Restart();
141 break;
142 case TPM_SIGNAL_PHYS_PRES_ON:
143 _rpc__Signal_PhysicalPresenceOn();
144 break;
145 case TPM_SIGNAL_PHYS_PRES_OFF:
146 _rpc__Signal_PhysicalPresenceOff();
147 break;
148 case TPM_SIGNAL_CANCEL_ON:
149 _rpc__Signal_CancelOn();
150 break;
151 case TPM_SIGNAL_CANCEL_OFF:
152 _rpc__Signal_CancelOff();
153 break;
154 case TPM_SIGNAL_NV_ON:
155 _rpc__Signal_NvOn();
156 break;
157 case TPM_SIGNAL_NV_OFF:
158 _rpc__Signal_NvOff();
159 break;
160 case TPM_SIGNAL_KEY_CACHE_ON:
161 _rpc__RsaKeyCacheControl(TRUE);
162 break;
163 case TPM_SIGNAL_KEY_CACHE_OFF:
164 _rpc__RsaKeyCacheControl(FALSE);
165 break;
166 case TPM_SESSION_END:
167 // Client signaled end-of-session
168 TpmEndSimulation();
169 return TRUE;
170 case TPM_STOP:
171 // Client requested the simulator to exit
172 return FALSE;
173 case TPM_TEST_FAILURE_MODE:
174 _rpc__ForceFailureMode();
175 break;
176 case TPM_GET_COMMAND_RESPONSE_SIZES:
D.3.2.2. PlatformSvcRoutine()
This function is called to set up the socket interfaces to listen for commands.
D.3.2.3. PlatformSignalService()
This function starts a new thread waiting for platform signals. Platform signals are processed one at a
time in the order in which they are received.
244 int
245 PlatformSignalService(
246 int PortNumber
247 )
248 {
249 #if defined(_MSC_VER)
250 HANDLE hPlatformSvc;
251 int ThreadId;
252 int port = PortNumber;
253 //
254 // Create service thread for platform signals
255 hPlatformSvc = CreateThread(NULL, 0,
256 (LPTHREAD_START_ROUTINE)PlatformSvcRoutine,
257 (LPVOID)(INT_PTR)port, 0, (LPDWORD)&ThreadId);
258 if(hPlatformSvc == NULL)
259 {
260 printf("Thread Creation failed\n");
261 return -1;
262 }
263 return 0;
264 #else
265 pthread_t thread_id;
266 int ret;
267 int port = PortNumber;
268
269 ret = pthread_create(&thread_id, NULL, (void*)PlatformSvcRoutine,
270 (LPVOID)(INT_PTR)port);
271 if (ret == -1)
272 {
273 printf("pthread_create failed: %s", strerror(ret));
274 }
275 return ret;
276 #endif // _MSC_VER
277 }
D.3.2.4. RegularCommandService()
278 int
279 RegularCommandService(
280 int PortNumber
281 )
282 {
283 SOCKET listenSocket;
284 SOCKET serverSocket;
285 struct sockaddr_in HerAddress;
286 int res;
287 socklen_t length;
D.3.2.5. SimulatorTimeServiceRoutine()
347
348 // May need to issue several ticks if the Sleep() took longer than asked,
349 // or no ticks at all, it Sleep() was interrupted prematurely.
350 while (prevTime < curTime - tick / 2)
351 {
352 //printf("%05lld | %05lld\n",
353 // prevTime % 100000, (curTime - tick / 2) % 100000);
354 _plat__ACT_Tick();
355 prevTime += (UINT64)tick;
356 }
357 // Adjust the next timeout to keep the average interval of one second
358 timeout = tick + (prevTime - curTime);
359 //prevTime = curTime;
360 //printf("%04lld | c:%05lld | p:%05llu\n",
361 // timeout, curTime % 100000, prevTime);
362 }
363 return 0;
364 }
D.3.2.6. ActTimeService()
This function starts a new thread waiting to wait for time ticks.
D.3.2.7. StartTcpServer()
This is the main entry-point to the TCP server. The server listens on port specified.
Note that there is no way to specify the network interface in this implementation.
405 int
406 StartTcpServer(
407 int PortNumber
408 )
409 {
410 int res;
411 //
412 #if RH_ACT_0 || 1
413 // Start the Time Service routine
414 res = ActTimeService();
415 if(res != 0)
416 {
417 printf("TimeService failed\n");
418 return res;
419 }
420 #endif
421
422 // Start Platform Signal Processing Service
423 res = PlatformSignalService(PortNumber + 1);
424 if(res != 0)
425 {
426 printf("PlatformSignalService failed\n");
427 return res;
428 }
429 // Start Regular/DRTM TPM command service
430 res = RegularCommandService(PortNumber);
431 if(res != 0)
432 {
433 printf("RegularCommandService failed\n");
434 return res;
435 }
436 return 0;
437 }
D.3.2.8. ReadBytes()
This function reads the indicated number of bytes (NumBytes) into buffer from the indicated socket.
438 BOOL
439 ReadBytes(
440 SOCKET s,
441 char *buffer,
442 int NumBytes
443 )
444 {
445 int res;
446 int numGot = 0;
447 //
448 while(numGot < NumBytes)
449 {
450 res = recv(s, buffer + numGot, NumBytes - numGot, 0);
D.3.2.9. WriteBytes()
This function will send the indicated number of bytes (NumBytes) to the indicated socket
464 BOOL
465 WriteBytes(
466 SOCKET s,
467 char *buffer,
468 int NumBytes
469 )
470 {
471 int res;
472 int numSent = 0;
473 //
474 while(numSent < NumBytes)
475 {
476 res = send(s, buffer + numSent, NumBytes - numSent, 0);
477 if(res == -1)
478 {
479 if(WSAGetLastError() == 0x2745)
480 {
481 printf("Client disconnected\n");
482 }
483 else
484 {
485 printf("Send error. Error is 0x%x\n", WSAGetLastError());
486 }
487 return FALSE;
488 }
489 numSent += res;
490 }
491 return TRUE;
492 }
D.3.2.10. WriteUINT32()
493 BOOL
494 WriteUINT32(
495 SOCKET s,
496 uint32_t val
497 )
498 {
499 UINT32 netVal = htonl(val);
500 //
501 return WriteBytes(s, (char*)&netVal, 4);
502 }
D.3.2.11. ReadUINT32()
503 BOOL
504 ReadUINT32(
505 SOCKET s,
506 UINT32 *val
507 )
508 {
509 UINT32 netVal;
510 //
511 if (!ReadBytes(s, (char*)&netVal, 4))
512 return FALSE;
513 *val = ntohl(netVal);
514 return TRUE;
515 }
D.3.2.12. ReadVarBytes()
Get a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big-
endian).
516 BOOL
517 ReadVarBytes(
518 SOCKET s,
519 char *buffer,
520 uint32_t *BytesReceived,
521 int MaxLen
522 )
523 {
524 int length;
525 BOOL res;
526 //
527 res = ReadBytes(s, (char*)&length, 4);
528 if(!res) return res;
529 length = ntohl(length);
530 *BytesReceived = length;
531 if(length > MaxLen)
532 {
533 printf("Buffer too big. Client says %d\n", length);
534 return FALSE;
535 }
536 if(length == 0) return TRUE;
537 res = ReadBytes(s, buffer, length);
538 if(!res) return res;
539 return TRUE;
540 }
D.3.2.13. WriteVarBytes()
Send a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big-
endian).
541 BOOL
542 WriteVarBytes(
543 SOCKET s,
544 char *buffer,
545 int BytesToSend
546 )
547 {
548 uint32_t netLength = htonl(BytesToSend);
D.3.2.14. TpmServer()
Processing incoming TPM command requests using the protocol / interface defined above.
559 BOOL
560 TpmServer(
561 SOCKET s
562 )
563 {
564 uint32_t length;
565 uint32_t Command;
566 BYTE locality;
567 BOOL OK;
568 int result;
569 int clientVersion;
570 _IN_BUFFER InBuffer;
571 _OUT_BUFFER OutBuffer;
572 //
573 for(;;)
574 {
575 OK = ReadBytes(s, (char*)&Command, 4);
576 // client disconnected (or other error). We stop processing this client
577 // and return to our caller who can stop the server or listen for another
578 // connection.
579 if(!OK)
580 return TRUE;
581 Command = ntohl(Command);
582 switch(Command)
583 {
584 case TPM_SIGNAL_HASH_START:
585 _rpc__Signal_Hash_Start();
586 break;
587 case TPM_SIGNAL_HASH_END:
588 _rpc__Signal_HashEnd();
589 break;
590 case TPM_SIGNAL_HASH_DATA:
591 OK = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
592 if(!OK) return TRUE;
593 InBuffer.Buffer = (BYTE*)InputBuffer;
594 InBuffer.BufferSize = length;
595 _rpc__Signal_Hash_Data(InBuffer);
596 break;
597 case TPM_SEND_COMMAND:
598 OK = ReadBytes(s, (char*)&locality, 1);
599 if(!OK)
600 return TRUE;
601 OK = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
602 if(!OK)
603 return TRUE;
604 InBuffer.Buffer = (BYTE*)InputBuffer;
605 InBuffer.BufferSize = length;
606 OutBuffer.BufferSize = MAX_BUFFER;
607 OutBuffer.Buffer = (_OUTPUT_BUFFER)OutputBuffer;
D.4 TPMCmdp.c
D.4.1. Description
This file contains the functions that process the commands received on the control port or the command
port of the simulator. The control port is used to allow simulation of hardware events (such as,
_TPM_Hash_Start()) to test the simulated TPM's reaction to those events. This improves code coverage
of the testing.
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <setjmp.h>
4 #include "TpmBuildSwitches.h"
5 #ifdef _MSC_VER
6 # pragma warning(push, 3)
7 # include <windows.h>
8 # include <winsock.h>
9 # pragma warning(pop)
10 #elif defined(__unix__)
11 typedef int SOCKET;
12 #else
13 # error "Unsupported platform."
14 #endif
15 #ifndef TRUE
16 # define TRUE 1
17 #endif
18 #ifndef FALSE
19 # define FALSE 0
20 #endif
21 #include "Platform_fp.h"
22 #include "ExecCommand_fp.h"
23 #include "Manufacture_fp.h"
24 #include "_TPM_Init_fp.h"
25 #include "_TPM_Hash_Start_fp.h"
26 #include "_TPM_Hash_Data_fp.h"
27 #include "_TPM_Hash_End_fp.h"
28 #include "TpmFail_fp.h"
29 #include "TpmTcpProtocol.h"
30 #include "Simulator_fp.h"
31 static BOOL s_isPowerOn = FALSE;
32
33 //** Functions
34
35 //*** Signal_PowerOn()
36 // This function processes a power-on indication. Among other things, it
37 // calls the _TPM_Init() handler.
38 void
39 _rpc__Signal_PowerOn(
40 BOOL isReset
41 )
42 {
43 // if power is on and this is not a call to do TPM reset then return
44 if(s_isPowerOn && !isReset)
45 return;
46 // If this is a reset but power is not on, then return
47 if(isReset && !s_isPowerOn)
48 return;
49 // Unless this is just a reset, pass power on signal to platform
50 if(!isReset)
51 _plat__Signal_PowerOn();
D.4.2.1. Signal_Restart()
This function processes the clock restart indication. All it does is call the platform function.
58 void
59 _rpc__Signal_Restart(
60 void
61 )
62 {
63 _plat__TimerRestart();
64 }
D.4.2.2. Signal_PowerOff()
This function processes the power off indication. Its primary function is to set a flag indicating that the
next power on indication should cause _TPM_Init() to be called.
65 void
66 _rpc__Signal_PowerOff(
67 void
68 )
69 {
70 if(s_isPowerOn)
71 // Pass power off signal to platform
72 _plat__Signal_PowerOff();
73 // This could be redundant, but...
74 s_isPowerOn = FALSE;
75
76 return;
77 }
D.4.2.3. _rpc__ForceFailureMode()
This function is used to debug the Failure Mode logic of the TPM. It will set a flag in the TPM code such
that the next call to TPM2_SelfTest() will result in a failure, putting the TPM into Failure Mode.
78 void
79 _rpc__ForceFailureMode(
80 void
81 )
82 {
83 SetForceFailureMode();
84 return;
85 }
D.4.2.4. _rpc__Signal_PhysicalPresenceOn()
86 void
87 _rpc__Signal_PhysicalPresenceOn(
88 void
89 )
90 {
91 // If TPM power is on
92 if(s_isPowerOn)
93 // Pass physical presence on to platform
94 _plat__Signal_PhysicalPresenceOn();
95 return;
96 }
D.4.2.5. _rpc__Signal_PhysicalPresenceOff()
97 void
98 _rpc__Signal_PhysicalPresenceOff(
99 void
100 )
101 {
102 // If TPM is power on
103 if(s_isPowerOn)
104 // Pass physical presence off to platform
105 _plat__Signal_PhysicalPresenceOff();
106 return;
107 }
D.4.2.6. _rpc__Signal_Hash_Start()
108 void
109 _rpc__Signal_Hash_Start(
110 void
111 )
112 {
113 // If TPM power is on
114 if(s_isPowerOn)
115 // Pass _TPM_Hash_Start signal to TPM
116 _TPM_Hash_Start();
117 return;
118 }
D.4.2.7. _rpc__Signal_Hash_Data()
119 void
120 _rpc__Signal_Hash_Data(
121 _IN_BUFFER input
122 )
123 {
124 // If TPM power is on
125 if(s_isPowerOn)
126 // Pass _TPM_Hash_Data signal to TPM
127 _TPM_Hash_Data(input.BufferSize, input.Buffer);
128 return;
129 }
D.4.2.8. _rpc__Signal_HashEnd()
130 void
131 _rpc__Signal_HashEnd(
132 void
133 )
134 {
135 // If TPM power is on
136 if(s_isPowerOn)
137 // Pass _TPM_HashEnd signal to TPM
138 _TPM_Hash_End();
139 return;
140 }
D.4.2.9. _rpc__Send_Command()
141 void
142 _rpc__Send_Command(
143 unsigned char locality,
144 _IN_BUFFER request,
145 _OUT_BUFFER *response
146 )
147 {
148 // If TPM is power off, reject any commands.
149 if(!s_isPowerOn)
150 {
151 response->BufferSize = 0;
152 return;
153 }
154 // Set the locality of the command so that it doesn't change during the command
155 _plat__LocalitySet(locality);
156 // Do implementation-specific command dispatch
157 _plat__RunCommand(request.BufferSize, request.Buffer,
158 &response->BufferSize, &response->Buffer);
159 return;
160 }
D.4.2.10. _rpc__Signal_CancelOn()
This function is used to turn on the indication to cancel a command in process. An executing command is
not interrupted. The command code may periodically check this indication to see if it should abort the
current command processing and returned TPM_RC_CANCELLED.
161 void
162 _rpc__Signal_CancelOn(
163 void
164 )
165 {
166 // If TPM power is on
167 if(s_isPowerOn)
168 // Set the platform canceling flag.
169 _plat__SetCancel();
170 return;
171 }
D.4.2.11. _rpc__Signal_CancelOff()
This function is used to turn off the indication to cancel a command in process.
172 void
173 _rpc__Signal_CancelOff(
174 void
175 )
176 {
177 // If TPM power is on
178 if(s_isPowerOn)
179 // Set the platform canceling flag.
180 _plat__ClearCancel();
181 return;
182 }
D.4.2.12. _rpc__Signal_NvOn()
In a system where the NV memory used by the TPM is not within the TPM, the NV may not always be
available. This function turns on the indicator that indicates that NV is available.
183 void
184 _rpc__Signal_NvOn(
185 void
186 )
187 {
188 // If TPM power is on
189 if(s_isPowerOn)
190 // Make the NV available
191 _plat__SetNvAvail();
192 return;
193 }
D.4.2.13. _rpc__Signal_NvOff()
This function is used to set the indication that NV memory is no longer available.
194 void
195 _rpc__Signal_NvOff(
196 void
197 )
198 {
199 // If TPM power is on
200 if(s_isPowerOn)
201 // Make NV not available
202 _plat__ClearNvAvail();
203 return;
204 }
205 void RsaKeyCacheControl(int state);
D.4.2.14. _rpc__RsaKeyCacheControl()
This function is used to enable/disable the use of the RSA key cache during simulation.
206 void
207 _rpc__RsaKeyCacheControl(
208 int state
209 )
210 {
211 #if USE_RSA_KEY_CACHE
212 RsaKeyCacheControl(state);
213 #else
214 NOT_REFERENCED(state);
215 #endif
216 return;
217 }
218 #define TPM_RH_ACT_0 0x40000110
D.4.2.15. _rpc__ACT_GetSignaled()
219 BOOL
220 _rpc__ACT_GetSignaled(
221 UINT32 actHandle
222 )
223 {
224 // If TPM power is on
225 if (s_isPowerOn)
226 // Query the platform
227 return _plat__ACT_GetSignaled(actHandle - TPM_RH_ACT_0);
228 return FALSE;
229 }
D.5 TPMCmds.c
D.5.1. Description
1 #include "TpmBuildSwitches.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <stdint.h>
5 #include <ctype.h>
6 #include <string.h>
7 #ifdef _MSC_VER
8 # pragma warning(push, 3)
9 # include <windows.h>
10 # include <winsock.h>
11 # pragma warning(pop)
12 #elif defined(__unix__)
13 # define _strcmpi strcasecmp
14 typedef int SOCKET;
15 #else
16 # error "Unsupported platform."
17 #endif
18 #ifndef TRUE
19 # define TRUE 1
20 #endif
21 #ifndef FALSE
22 # define FALSE 0
23 #endif
24 #include "TpmTcpProtocol.h"
25 #include "Manufacture_fp.h"
26 #include "Platform_fp.h"
27 #include "Simulator_fp.h"
28 #define PURPOSE \
29 "TPM 2.0 Reference Simulator.\n" \
30 "Copyright (c) Microsoft Corporation. All rights reserved."
31 #define DEFAULT_TPM_PORT 2321
Information about command line arguments (does not include program name)
52 #endif
D.5.2.1. Usage()
This function prints the proper calling sequence for the simulator.
53 static void
54 Usage(
55 const char *programName
56 )
57 {
58 fprintf(stderr, "%s\n\n", PURPOSE);
59 fprintf(stderr, "Usage: %s [PortNum] [opts]\n\n"
60 "Starts the TPM server listening on TCP port PortNum (by default %d).\n\n"
61 "An option can be in the short form (one letter preceded with '-' or '/')\n"
62 "or in the full form (preceded with '--' or no option marker at all).\n"
63 "Possible options are:\n"
64 " -h (--help) or ? - print this message\n"
65 " -m (--manufacture) - forces NV state of the TPM simulator to be "
66 "(re)manufactured\n",
67 programName, DEFAULT_TPM_PORT);
68 exit(1);
69 }
D.5.2.2. CmdLineParser_Init()
70 static BOOL
71 CmdLineParser_Init(
72 int argc,
73 char *argv[],
74 int maxOpts
75 )
76 {
77 if (argc == 1)
78 return FALSE;
79
80 if (maxOpts && (argc - 1) > maxOpts)
81 {
82 fprintf(stderr, "No more than %d options can be specified\n\n", maxOpts);
83 Usage(argv[0]);
84 }
85
86 s_Argc = argc - 1;
87 s_Argv = (const char**)(argv + 1);
88 s_ArgsMask = (1 << s_Argc) - 1;
89 return TRUE;
90 }
D.5.2.3. CmdLineParser_More()
91 static BOOL
92 CmdLineParser_More(
93 void
94 )
95 {
96 return s_ArgsMask != 0;
97 }
D.5.2.4. CmdLineParser_IsOpt()
This function determines if the given command line parameter represents a valid option.
98 static BOOL
99 CmdLineParser_IsOpt(
100 const char* opt, // Command line parameter to check
101 const char* optFull, // Expected full name
102 const char* optShort, // Expected short (single letter) name
103 BOOL dashed // The parameter is preceded by a single dash
104 )
105 {
106 return 0 == strcmp(opt, optFull)
107 || (optShort && opt[0] == optShort[0] && opt[1] == 0)
108 || (dashed && opt[0] == '-' && 0 == strcmp(opt + 1, optFull));
109 }
D.5.2.5. CmdLineParser_IsOptPresent()
This function determines if the given command line parameter represents a valid option.
D.5.2.6. CmdLineParser_IsOptPresent()
This function notifies the parser that no more options are needed.
D.5.2.7. main()
This is the main entry point for the simulator. It registers the interface and starts listening for clients
171 int
172 main(
173 int argc,
174 char *argv[]
175 )
176 {
177 BOOL manufacture = FALSE;
178 int PortNum = DEFAULT_TPM_PORT;
179
180 // Parse command line options
181
182 if (CmdLineParser_Init(argc, argv, 2))
183 {
184 if ( CmdLineParser_IsOptPresent("?", "?")
185 || CmdLineParser_IsOptPresent("help", "h"))
186 {
187 Usage(argv[0]);
188 }
189 if (CmdLineParser_IsOptPresent("manufacture", "m"))
190 {
191 manufacture = TRUE;
192 }
193 if (CmdLineParser_More())
194 {
195 int i;
196 for (i = 0; i < s_Argc; ++i)
197 {
198 char *nptr = NULL;
199 int portNum = (int)strtol(s_Argv[i], &nptr, 0);
200 if (s_Argv[i] != nptr)
201 {
202 // A numeric option is found
203 if(!*nptr && portNum > 0 && portNum < 65535)
204 {