Family "2.0"
Level 00 Revision 01.16
October 30, 2014
Published
Contact: admin@trustedcomputinggroup.org
Copyright © TCG 2006-2014
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 (admin@trustedcomputinggroup.org) 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 owner.
CONTENTS
Page vi TCG Published Family "2.0"
Family "2.0" TCG Published Page xi
Annex A (informative) Implementation Dependent 344
Annex B (informative) Cryptographic Library Interface 359
B.13.3.2.30. _cpri__C_2_2_KeyExchange() 515
Annex C (informative) Simulation Environment 517
Annex D (informative) Remote Procedure Interface 542
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.
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 to 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 tables in the TPM 2.0 Part 2 Annexes are constructed so that they can be processed by a program. The program that processes these tables in the TPM 2.0 Part 2 Annexes is called "The TPM 2.0 Part 2 Configuration Parser."
The tables in the TPM 2.0 Part 2 Annexes determine the configuration of a TPM implementation. These tables may be modified by an implementer to describe the algorithms and commands to be executed in by a specific implementation as well as to set implementation limits such as the number of PCR, sizes of buffers, etc.
The TPM 2.0 Part 2 Configuration Parser produces a set of structures and definitions that are used by the TPM 2.0 Part 2 Structure Parser.
The program that processes the tables in TPM 2.0 Part 2 (other than the table in the annexes) 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:
TPM_RC TYPE_Unmarshal(TYPE *target, BYTE **buffer, INT32 *size);
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.
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:
TPM_RC TYPE_Unmarshal(TYPE *target, BYTE **buffer, INT32 *size, UINT32 selector);
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
TPM_RC TYPE_Unmarshal(TYPE *target, BYTE **buffer, INT32 *size, bool flag);
The parser detects when the type allows a “null” value and will always include flag in any call to unmarshal that type.
Any data type may be included in an array. The function prototype use to unmarshal an array for a TYPE is
TPM_RC TYPE_Array_Unmarshal(TYPE *target, BYTE **buffer, INT32 *size,INT32 count);
The generated code for an array uses a count-limited loop within which it calls the unmarshaling code for
TYPE.
Marshaling Code Function Prototypes
The general form for the unmarshaling code for a simple type or a structure is:
UINT16 TYPE_Marshal(TYPE *source, BYTE **buffer, INT32 *size);
Where:
TYPE name of the data type or structure
*source location in the TPM memory containing the value that is to be marshaled in to the designated buffer
**buffer location in the output buffer where the first octet of the TYPE is to be placed
*size number of octets remaining in **buffer. If size is a NULL pointer, then no data is marshaled and the routine will compute the size of the memory required to marshal the indicated type
When the data is successfully marshaled, the called routine will return the number of octets marshaled into **buffer.
If the data is successfully marshaled, *buffer is advanced point to the first octet of the next location in the output buffer and *size is reduced by the number of octets placed in the buffer.
When the data type is a simple type, the parser will generate code that will marshal the underlying type. The presumption is that the TPM internal structures are consistent and correct so the marshaling code does not validate that the data placed in the buffer has a permissible value.
When the data type is a structure, the parser will generate code that marshals each of the structure elements in turn.
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:
UINT16 TYPE_Marshal(TYPE *target, BYTE **buffer, INT32 *size, UINT32 selector);
The parameters have a similar meaning as those in 5.2.2.2 but the data movement is from source to
buffer.
Any type may be included in an array. The function prototype use to unmarshal an array is:
UINT16 TYPE_Array_Marshal(TYPE *source, BYTE **buffer, INT32 *size, INT32 count);
The generated code for an array uses a count-limited loop within which it calls the marshaling code for
TYPE.
The program that processes the tables in TPM 2.0 Part 3 is called "The TPM 2.0 Part 3 Command Parser."
The TPM 2.0 Part 3 Command Parser takes as input a TPM 2.0 Part 3 of the TPM specification and some configuration files produced by the TPM 2.0 Part 2 Configuration Parser. This parser uses the contents of the command and response tables in TPM 2.0 Part 3 to produce unmarshaling code for the command and the marshaling code for the response. Additionally, this parser produces support routines that are used to check that the proper number of authorization values of the proper type have been provided. These support routines are called by the functions in this TPM 2.0 Part 4.
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 0th 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 0th 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).
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.
#ifndef _BASETYPES_H
#define _BASETYPES_H
#include "stdint.h"
NULL definition
#ifndef NULL
#define NULL (0)
#endif
typedef uint8_t UINT8;
typedef uint8_t BYTE;
typedef int8_t INT8;
typedef int BOOL;
typedef uint16_t UINT16;
typedef int16_t INT16;
typedef uint32_t UINT32;
typedef int32_t INT32;
typedef uint64_t UINT64;
typedef int64_t INT64;
typedef struct {
UINT16 size;
BYTE buffer[1];
} TPM2B;
21 #endif
1 | #ifndef | _BITS_H | |
2 | #define | _BITS_H | |
3 | #define | CLEAR_BIT(bit, vector) | BitClear((bit), (BYTE *)&(vector), sizeof(vector)) |
4 | #define | SET_BIT(bit, vector) | BitSet((bit), (BYTE *)&(vector), sizeof(vector)) |
5 | #define | TEST_BIT(bit, vector) | BitIsSet((bit), (BYTE *)&(vector), sizeof(vector)) |
6 | #endif |
#ifndef _BOOL_H
#define _BOOL_H
#if defined(TRUE)
#undef TRUE
#endif
#if defined FALSE
#undef FALSE
#endif
typedef int BOOL;
#define FALSE ((BOOL)0)
#define TRUE ((BOOL)1)
12 #endif
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.
EXAMPLE PCR.c contains PCRCapGetHandles() and PCRCapGetProperties().
#ifndef _CAPABILITIES_H
#define _CAPABILITIES_H
#define MAX_CAP_DATA (MAX_CAP_BUFFER-sizeof(TPM_CAP)-sizeof(UINT32))
#define MAX_CAP_ALGS (ALG_LAST_VALUE - ALG_FIRST_VALUE + 1)
#define MAX_CAP_HANDLES (MAX_CAP_DATA/sizeof(TPM_HANDLE))
#define MAX_CAP_CC ((TPM_CC_LAST - TPM_CC_FIRST) + 1)
#define MAX_TPM_PROPERTIES (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))
#define MAX_PCR_PROPERTIES (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PCR_SELECT))
#define MAX_ECC_CURVES (MAX_CAP_DATA/sizeof(TPM_ECC_CURVE))
10 #endif
This file contains extra TPM2B structures
#ifndef _TPMB_H
#define _TPMB_H
This macro helps avoid having to type in the structure in order to create a new TPM2B type that is used in a function.
#define TPM2B_TYPE(name, bytes) \
typedef union { \
struct { \
UINT16 size; \
BYTE buffer[(bytes)]; \
8 } t; \
9 TPM2B b; \
} TPM2B_##name
Macro to instance and initialize a TPM2B value
#define TPM2B_INIT(TYPE, name) \
TPM2B_##TYPE name = {sizeof(name.t.buffer), {0}}
#define TPM2B_BYTE_VALUE(bytes) TPM2B_TYPE(bytes##_BYTE_VALUE, bytes)
14 #endif
#ifndef _TPM_ERROR_H
#define _TPM_ERROR_H
#include "TpmBuildSwitches.h"
#define FATAL_ERROR_ALLOCATION (1)
#define FATAL_ERROR_DIVIDE_ZERO (2)
#define FATAL_ERROR_INTERNAL (3)
#define FATAL_ERROR_PARAMETER (4)
#define FATAL_ERROR_ENTROPY (5)
#define FATAL_ERROR_SELF_TEST (6)
#define FATAL_ERROR_CRYPTO (7)
#define FATAL_ERROR_NV_UNRECOVERABLE (8)
#define FATAL_ERROR_REMANUFACTURED (9) // indicates that the TPM has
// been re-manufactured after an
// unrecoverable NV error
#define FATAL_ERROR_DRBG (10)
#define FATAL_ERROR_FORCED (666)
These are the crypto assertion routines. When a function returns an unexpected and unrecoverable result, the assertion fails and the TpmFail() is called
void
TpmFail(const char *function, int line, int code);
typedef void (*FAIL_FUNCTION)(const char *, int, int);
#define FAIL(a) (TpmFail( FUNCTION , LINE , a))
#if defined(EMPTY_ASSERT)
# define pAssert(a) ((void)0)
#else
# define pAssert(a) (!!(a) ? 1 : (FAIL(FATAL_ERROR_PARAMETER), 0))
#endif
26 #endif // _TPM_ERROR_H
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.
#ifndef GLOBAL_H
#define GLOBAL_H
//#define SELF_TEST
#include "TpmBuildSwitches.h"
#include "Tpm.h"
#include "TPMB.h"
#include "CryptoEngine.h"
#include <setjmp.h>
This define is used to eliminate the compiler warning about an unreferenced parameter. Basically, it tells the compiler that it is not an accident that the parameter is unreferenced.
#ifndef UNREFERENCED_PARAMETER
# define UNREFERENCED_PARAMETER(a) (a)
#endif
#include "bits.h"
Define these values here if the AlgorithmTests() project is not used
#ifndef SELF_TEST
extern ALGORITHM_VECTOR g_implementedAlgorithms;
extern ALGORITHM_VECTOR g_toTest;
#else
LIB_IMPORT extern ALGORITHM_VECTOR g_implementedAlgorithms;
LIB_IMPORT extern ALGORITHM_VECTOR g_toTest;
#endif
These macros are used in CryptUtil() to invoke the incremental self test.
#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.
21 | #define | TEST_HASH(alg) | \ |
22 | if( TEST_BIT(alg, g_toTest) | \ | |
23 | && (alg != ALG_NULL_VALUE)) | \ | |
24 | CryptTestAlgorithm(alg, NULL) |
Hash and HMAC State Structures
These definitions are for the types that can be in a hash state structure. These types are used in the crypto utilities
typedef BYTE HASH_STATE_TYPE;
#define HASH_STATE_EMPTY ((HASH_STATE_TYPE) 0)
#define HASH_STATE_HASH ((HASH_STATE_TYPE) 1)
#define HASH_STATE_HMAC ((HASH_STATE_TYPE) 2)
A HASH_STATE structure contains an opaque hash stack state. A caller would use this structure when performing incremental hash operations. The state is updated on each call. If type is an HMAC_STATE, or HMAC_STATE_SEQUENCE then state is followed by the HMAC key in oPad format.
typedef struct 30 {
CPRI_HASH_STATE state; // hash state
HASH_STATE_TYPE type; // type of the context
} HASH_STATE;
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.
typedef struct 35 {
HASH_STATE hashState; // the hash state
TPM2B_HASH_BLOCK hmacKey; // the HMAC key
} HMAC_STATE;
An AUTH_VALUE is a BYTE array containing a digest (TPMU_HA)
typedef BYTE AUTH_VALUE[sizeof(TPMU_HA)];
A TIME_INFO is a BYTE array that can contain a TPMS_TIME_INFO
typedef BYTE TIME_INFO[sizeof(TPMS_TIME_INFO)];
A NAME is a BYTE array that can contain a TPMU_NAME
typedef BYTE NAME[sizeof(TPMU_NAME)];
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.
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.
typedef struct 43 {
unsigned publicOnly : 1; //0) SET if only the public portion of
// an object is loaded
unsigned epsHierarchy : 1; //1) SET if the object belongs to EPS
// Hierarchy
unsigned ppsHierarchy : 1; //2) SET if the object belongs to PPS
// Hierarchy
unsigned spsHierarchy : 1; //3) SET f the object belongs to SPS
// Hierarchy
unsigned evict : 1; //4) SET if the object is a platform or
// owner evict object. Platform-
// evict object belongs to PPS
// hierarchy, owner-evict object
// belongs to SPS or EPS hierarchy.
// This bit is also used to mark a
// completed sequence object so it
// will be flush when the
// SequenceComplete command succeeds.
unsigned primary : 1; //5) SET for a primary object
62 | unsigned | temporary : | 1; | //6) | SET | for a temporary object |
63 | unsigned | stClear : | 1; | //7) | SET | for an stClear object |
64 | unsigned | hmacSeq : | 1; | //8) | SET | for an HMAC sequence object |
65 | unsigned | hashSeq : | 1; | //9) | SET | for a hash sequence object |
66 | unsigned | eventSeq : | 1; | //10) | SET | for an event sequence object |
67 | unsigned | ticketSafe : | 1; | //11) | SET | if a ticket is safe to create |
68 | // | for | hash sequence object | |||
69 | unsigned | firstBlock : | 1; | //12) | SET | if the first block of hash |
70 | // | data has been received. It | ||||
71 | // | works with ticketSafe bit | ||||
72 | unsigned | isParent : | 1; | //13) | SET if the key has the proper | |
73 | // | attributes to be a parent key | ||||
74 | unsigned | privateExp : | 1; | //14) | SET when the private exponent | |
75 | // | of an RSA key has been validated. | ||||
76 | unsigned | reserved | : 1; | //15) reserved bits. unused. | ||
77 | } OBJECT_ATTRIBUTES; |
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.
78 typedef struct 79 {
// The attributes field is required to be first followed by the publicArea.
// This allows the overlay of the object structure and a sequence structure
OBJECT_ATTRIBUTES attributes; // object attributes
TPMT_PUBLIC publicArea; // public area of an object
TPMT_SENSITIVE sensitive; // sensitive area of an object 85
#ifdef TPM_ALG_RSA
TPM2B_PUBLIC_KEY_RSA privateExponent; // Additional field for the private
// exponent of an RSA key.
#endif
TPM2B_NAME qualifiedName; // object qualified name
TPMI_DH_OBJECT evictHandle; // if the object is an evict object,
// the original handle is kept here.
// The 'working' handle will be the
// handle of an object slot.
95
TPM2B_NAME name; // Name of the object name. Kept here
// to avoid repeatedly computing it.
} OBJECT;
This structure holds a hash sequence object or an event sequence object.
The first four components of this structure are manually set to be the same as the first four components of the object structure. This prevents the object from being inadvertently misused as sequence objects occupy the same memory as a regular object. A debug check is present to make sure that the offsets are what they are supposed to be.
typedef struct
100 {
OBJECT_ATTRIBUTES attributes; // The attributes of the HASH object
TPMI_ALG_PUBLIC type; // algorithm
TPMI_ALG_HASH nameAlg; // name algorithm
TPMA_OBJECT objectAttributes; // object attributes
105
// The data below is unique to a sequence object
TPM2B_AUTH auth; // auth for use of sequence
union
109 {
HASH_STATE hashState[HASH_COUNT];
HMAC_STATE hmacState;
} state;
} HASH_OBJECT;
This is the union for holding either a sequence object or a regular object.
typedef union
115 {
OBJECT entity;
HASH_OBJECT hash;
} ANY_OBJECT;
These values are used in the authorization processing.
119 | typedef | UINT32 | AUTH_ROLE; |
120 | #define | AUTH_NONE | ((AUTH_ROLE)(0)) |
121 | #define | AUTH_USER | ((AUTH_ROLE)(1)) |
122 | #define | AUTH_ADMIN | ((AUTH_ROLE)(2)) |
123 | #define | AUTH_DUP | ((AUTH_ROLE)(3)) |
The structures in this section define the internal structure of a session context.
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.
124 typedef struct
125 {
unsigned isPolicy : 1; //1) SET if the session may only
// be used for policy
unsigned isAudit : 1; //2) SET if the session is used
// for audit
unsigned isBound : 1; //3) SET if the session is bound to
// with an entity.
// This attribute will be CLEAR if
// either isPolicy or isAudit is SET.
unsigned iscpHashDefined : 1;//4) SET if the cpHash has been defined
// This attribute is not SET unless
// 'isPolicy' is SET.
unsigned isAuthValueNeeded : 1;
//5) SET if the authValue is required
// for computing the session HMAC.
// This attribute is not SET unless
141 | // isPolicy is SET. | |
142 | unsigned | isPasswordNeeded : 1; |
143 | //6) SET if a password authValue is | |
144 | // required for authorization | |
145 | // This attribute is not SET unless | |
146 | // isPolicy is SET. | |
147 | unsigned | isPPRequired : 1; //7) SET if physical presence is |
148 | // required to be asserted when the | |
149 | // authorization is checked. | |
150 | // This attribute is not SET unless | |
151 | // isPolicy is SET. | |
152 | unsigned | isTrialPolicy : 1; //8) SET if the policy session is |
153 | // created for trial of the policy's | |
154 | // policyHash generation. | |
155 | // This attribute is not SET unless | |
156 | // isPolicy is SET. | |
157 | unsigned | isDaBound : 1; //9) SET if the bind entity had noDA |
158 | // CLEAR. If this is SET, then an | |
159 | // auth failure using this session | |
160 | // will count against lockout even | |
161 | // if the object being authorized is | |
162 | // exempt from DA. | |
163 | unsigned | isLockoutBound : 1; //10)SET if the session is bound to |
164 | // lockoutAuth. | |
165 | unsigned | requestWasBound : 1;//11) SET if the session is being used |
166 | // with the bind entity. If SET | |
167 | // the authValue will not be use | |
168 | // in the response HMAC computation. | |
169 | unsigned | checkNvWritten : 1; //12) SET if the TPMA_NV_WRITTEN |
170 | // attribute needs to be checked | |
171 | // when the policy is used for | |
172 | // authorization for NV access. | |
173 | // If this is SET for any other | |
174 | // type, the policy will fail. | |
175 | unsigned | nvWrittenState : 1; //13) SET if TPMA_NV_WRITTEN is |
176 | // required to be SET. | |
177 | } SESSION_ATTRIBUTES; |
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.
178 | typedef struct | |||
179 | { | |||
180 | TPM_ALG_ID | authHashAlg; | // | session hash algorithm |
181 | TPM2B_NONCE | nonceTPM; | // | last TPM-generated nonce for |
182 | // | this session | ||
183 | ||||
184 | TPMT_SYM_DEF | symmetric; | // | session symmetric algorithm (if any) |
185 | TPM2B_AUTH | sessionKey; | // | session secret value used for |
186 | // | generating HMAC and encryption keys | ||
187 | ||||
188 | SESSION_ATTRIBUTES | attributes; | // | session attributes |
189 | TPM_CC | commandCode; | // | command code (policy session) |
190 | TPMA_LOCALITY | commandLocality; | // | command locality (policy session) |
191 | UINT32 | pcrCounter; | // | PCR counter value when PCR is |
192 | // | included (policy session) | ||
193 | // | If no PCR is included, this | ||
194 | // | value is 0. | ||
195 | ||||
196 | UINT64 | startTime; | // | value of TPMS_CLOCK_INFO.clock when |
197 | // | the session was started (policy |
198 | // | session) | ||
199 | ||||
200 | UINT64 | timeOut; | // | timeout relative to |
201 | // | TPMS_CLOCK_INFO.clock | ||
202 | // | There is no timeout if this value | ||
203 | // | is 0. | ||
204 | union | |||
205 | { | |||
206 | TPM2B_NAME | boundEntity; | // | value used to track the entity to |
207 | // | which the session is bound | ||
208 | ||||
209 | TPM2B_DIGEST | cpHash; | // | the required cpHash value for the |
210 | // | command being authorized | ||
211 | ||||
212 | } u1; | // | 'boundEntity' and 'cpHash' may | |
213 | // | share the same space to save memory | ||
214 | ||||
215 | union | |||
216 | { | |||
217 | TPM2B_DIGEST | auditDigest; | // | audit session digest |
218 | TPM2B_DIGEST | policyDigest; | // policyHash | |
219 | ||||
220 | } | u2; | // audit log and policyHash may | |
221 | // share space to save memory | |||
222 | } SESSION; |
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.
223 typedef struct
224 {
#ifdef TPM_ALG_SHA1
BYTE sha1[NUM_STATIC_PCR][SHA1_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA256
BYTE sha256[NUM_STATIC_PCR][SHA256_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA384
BYTE sha384[NUM_STATIC_PCR][SHA384_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA512
BYTE sha512[NUM_STATIC_PCR][SHA512_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SM3_256
BYTE sm3_256[NUM_STATIC_PCR][SM3_256_DIGEST_SIZE];
#endif 240
// This counter increments whenever the PCR are updated.
// NOTE: A platform-specific specification may designate
// certain PCR changes as not causing this counter
// to increment.
UINT32 pcrCounter; 246
247 } PCR_SAVE;
This structure holds the PCR policies, one for each group of PCR controlled by policy. | |||
248 | typedef struct | ||
249 | { | ||
250 | TPMI_ALG_HASH hashAlg[NUM_POLICY_PCR_GROUP]; | ||
251 | TPM2B_DIGEST a; | ||
252 | TPM2B_DIGEST policy[NUM_POLICY_PCR_GROUP]; | ||
253 | } PCR_POLICY; | ||
This structure holds the PCR policies, one for each group of PCR controlled by policy. | |||
254 | typedef struct | ||
255 | { | ||
256 | TPM2B_DIGEST auth[NUM_AUTHVALUE_PCR_GROUP]; | ||
257 | } PCR_AUTHVALUE; | ||
Part 2 defines the two shutdown/startup types that may be used in TPM2_Shutdown() | and | ||
TPM2_Starup(). This additional define is used by the TPM to indicate that no shutdown was received. | |||
NOTE: This is a reserved value. | |||
258 | #define SHUTDOWN_NONE (TPM_SU)(0xFFFF) | ||
This enumeration is the possible startup types. The type is determined by the combination | of | ||
TPM2_ShutDown() and TPM2_Startup(). | |||
259 | typedef enum | ||
260 | { | ||
261 | SU_RESET, | ||
262 | SU_RESTART, | ||
263 | SU_RESUME | ||
264 | } STARTUP_TYPE; |
This enumeration defines the master list of the elements of a reserved portion of NV. This list includes all the pre-defined data that takes space in NV, either as persistent data or as state save data. The enumerations are used as indexes into an array of offset values. The offset values then are used to index into NV. This is method provides an imperfect analog to an actual NV implementation.
265 typedef enum
266 {
// Entries below mirror the PERSISTENT_DATA structure. These values are written
// to NV as individual items.
// hierarchy
270 | NV_DISABLE_CLEAR, | |
271 | NV_OWNER_ALG, | |
272 | NV_ENDORSEMENT_ALG, | |
273 | NV_LOCKOUT_ALG, | |
274 | NV_OWNER_POLICY, | |
275 | NV_ENDORSEMENT_POLICY, | |
276 | NV_LOCKOUT_POLICY, | |
277 | NV_OWNER_AUTH, | |
278 | NV_ENDORSEMENT_AUTH, | |
279 | NV_LOCKOUT_AUTH, | |
280 | ||
281 | NV_EP_SEED, | |
282 | NV_SP_SEED, | |
283 | NV_PP_SEED, | |
284 | ||
285 | NV_PH_PROOF, | |
286 | NV_SH_PROOF, | |
287 | NV_EH_PROOF, | |
288 | ||
289 | // Time | |
290 | NV_TOTAL_RESET_COUNT, | |
291 | NV_RESET_COUNT, | |
292 | ||
293 | // PCR | |
294 | NV_PCR_POLICIES, | |
295 | NV_PCR_ALLOCATED, | |
296 | ||
297 | // Physical Presence | |
298 | NV_PP_LIST, | |
299 | ||
300 | // Dictionary Attack | |
301 | NV_FAILED_TRIES, | |
302 | NV_MAX_TRIES, | |
303 | NV_RECOVERY_TIME, | |
304 | NV_LOCKOUT_RECOVERY, | |
305 | NV_LOCKOUT_AUTH_ENABLED, | |
306 | ||
307 | // Orderly State flag | |
308 | NV_ORDERLY, | |
309 | ||
310 | // Command Audit | |
311 | NV_AUDIT_COMMANDS, | |
312 | NV_AUDIT_HASH_ALG, | |
313 | NV_AUDIT_COUNTER, | |
314 | ||
315 | // Algorithm Set | |
316 | NV_ALGORITHM_SET, | |
317 | ||
318 | NV_FIRMWARE_V1, | |
319 | NV_FIRMWARE_V2, | |
320 | ||
321 | // | The entries above are in PERSISTENT_DATA. The entries below represent |
322 | // | structures that are read and written as a unit. |
323 | ||
324 | // | ORDERLY_DATA data structure written on each orderly shutdown |
325 | NV_ORDERLY_DATA, | |
326 | ||
327 | // | STATE_CLEAR_DATA structure written on each Shutdown(STATE) |
328 | NV_STATE_CLEAR, | |
329 | ||
330 | // | STATE_RESET_DATA structure written on each Shutdown(STATE) |
331 | NV_STATE_RESET, | |
332 | ||
333 | NV_RESERVE_LAST // end of NV reserved data list |
} NV_RESERVE;
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.
typedef struct
336 {
TPMS_NV_PUBLIC publicArea;
TPM2B_AUTH authValue;
} NV_INDEX;
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.
#ifdef TPM_ALG_ECC
#define COMMIT_INDEX_MASK ((UINT16)((sizeof(gr.commitArray)*8)-1))
#endif
The values in this section are only extant in RAM. They are defined here and instanced in Global.c.
This array is used to contain the array of values that are added to a return code when it is a parameter-, handle-, or session-related error. This is an implementation choice and the same result can be achieved by using a macro.
extern const UINT16 g_rcIndex[15];
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.
extern TPM_HANDLE g_exclusiveAuditSession;
extern UINT64 g_time;
This is the platform hierarchy control and determines if the platform hierarchy is available. This value is SET on each TPM2_Startup(). The default value is SET.
extern BOOL g_phEnable;
This value is SET if a TPM2_PCR_Allocate() command successfully executed since the last TPM2_Startup(). If so, then the next shutdown is required to be Shutdown(CLEAR).
extern BOOL g_pcrReConfig;
This location indicates the sequence object handle that holds the DRTM sequence data. When not used, it is set to TPM_RH_UNASSIGNED. A sequence DRTM sequence is started on either _TPM_Init() or
_TPM_Hash_Start().
extern TPMI_DH_OBJECT g_DRTMHandle;
This value indicates that an H-CRTM occurred after _TPM_Init() but before TPM2_Startup(). The define for PRE_STARTUP_FLAG is used to add the g_DrtmPreStartup value to gp_orderlyState at shutdown. This hack is to avoid adding another NV variable.
349 | extern BOOL | g_DrtmPreStartup; |
350 | #define PRE_STARTUP_FLAG | 0x8000 |
This value indicates that a TPM2_Startup() occured at locality 3. Otherwise, it at locality 0. The define for STARTUP_LOCALITY_3 is to indicate that the startup was not at locality 0. This hack is to avoid adding another NV variable.
extern BOOL g_StartupLocality3;
#define STARTUP_LOCALITY_3 0x4000
This flag indicates if NV should be updated at the end of a command. This flag is set to FALSE at the beginning of each command in ExecuteCommand(). This flag is checked in ExecuteCommand() after the detailed actions of a command complete. If the command execution was successful and this flag is SET, any pending NV writes will be committed to NV.
extern BOOL g_updateNV;
This flag indicates if the execution of a command should cause the orderly state to be cleared. This flag is set to FALSE at the beginning of each command in ExecuteCommand() and is checked in ExecuteCommand() after the detailed actions of a command complete but before the check of g_updateNV. If this flag is TRUE, and the orderly state is not SHUTDOWN_NONE, then the orderly state in NV memory will be changed to SHUTDOWN_NONE.
extern BOOL g_clearOrderly;
This location indicates how the TPM was shut down before the most recent TPM2_Startup(). This value, along with the startup type, determines if the TPM should do a TPM Reset, TPM Restart, or TPM Resume.
extern TPM_SU g_prevOrderlyState;
This value indicates if the NV integrity check was successful or not. If not and the failure was severe, then the TPM would have been put into failure mode after it had been re-manufactured. If the NV failure was in the area where the state-save data is kept, then this variable will have a value of FALSE indicating that a TPM2_Startup(CLEAR) is required.
extern BOOL g_nvOk;
This location contains the unique value(s) used to identify the TPM. It is loaded on every
_TPM2_Startup() The first value is used to seed the RNG. The second value is used as a vendor authValue. The value used by the RNG would be the value derived from the chip unique value (such as fused) with a dependency on the authorities of the code in the TPM boot path. The second would be derived from the chip unique value with a dependency on the details of the code in the boot path. That is, the first value depends on the various signers of the code and the second depends on what was signed. The TPM vendor should not be able to know the first value but they are expected to know the second.
357 | extern | TPM2B_AUTH | g_platformUniqueAuthorities; // Reserved for RNG |
358 | extern | TPM2B_AUTH | g_platformUniqueDetails; // referenced by VENDOR_PERMANENT |
The values in this section are global values that are persistent across power events. The lifetime of the values determines the structure in which the value is placed.
This structure holds the persistent values that only change as a consequence of a specific Protected Capability and are not affected by TPM power events (TPM2_Startup() or TPM2_Shutdown().
359 typedef struct
360 {
361 //*********************************************************************************
362 // Hierarchy
363 //*********************************************************************************
364 // The values in this section are related to the hierarchies. 365
366 BOOL disableClear; // TRUE if TPM2_Clear() using
367 | ||
368 | ||
369 | // Hierarchy | authPolicies |
370 | TPMI_ALG_HASH | ownerAlg; |
371 | TPMI_ALG_HASH | endorsementAlg; |
372 | TPMI_ALG_HASH | lockoutAlg; |
373 | TPM2B_DIGEST | ownerPolicy; |
// lockoutAuth is disabled
TPM2B_DIGEST endorsementPolicy;
TPM2B_DIGEST lockoutPolicy; 376
// Hierarchy authValues
TPM2B_AUTH ownerAuth;
TPM2B_AUTH endorsementAuth;
TPM2B_AUTH lockoutAuth; 381
// Primary Seeds
TPM2B_SEED EPSeed;
TPM2B_SEED SPSeed;
TPM2B_SEED PPSeed;
// Note there is a nullSeed in the state_reset memory. 387
// Hierarchy proofs
TPM2B_AUTH phProof;
TPM2B_AUTH shProof;
TPM2B_AUTH ehProof;
// Note there is a nullProof in the state_reset memory. 393
394 //*********************************************************************************
395 // Reset Events
396 //*********************************************************************************
// A count that increments at each TPM reset and never get reset during the life
// time of TPM. The value of this counter is initialized to 1 during TPM
// manufacture process.
UINT64 totalResetCount; 401
402 // This counter increments on each TPM Reset. The counter is reset by
403 // TPM2_Clear().
404 UINT32 resetCount; 405
406 //*********************************************************************************
407 // PCR
408 //*********************************************************************************
409 // This structure hold the policies for those PCR that have an update policy.
410 // This implementation only supports a single group of PCR controlled by
411 // policy. If more are required, then this structure would be changed to
412 // an array.
413 PCR_POLICY pcrPolicies; 414
415 // This structure indicates the allocation of PCR. The structure contains a
416 // list of PCR allocations for each implemented algorithm. If no PCR are
417 // allocated for an algorithm, a list entry still exists but the bit map
418 // will contain no SET bits.
419 TPML_PCR_SELECTION pcrAllocated; 420
421 //*********************************************************************************
422 // Physical Presence
423 //*********************************************************************************
424 // The PP_LIST type contains a bit map of the commands that require physical
425 // to be asserted when the authorization is evaluated. Physical presence will be
426 // checked if the corresponding bit in the array is SET and if the authorization
427 // handle is TPM_RH_PLATFORM. 428 //
429 // These bits may be changed with TPM2_PP_Commands().
430 BYTE ppList[((TPM_CC_PP_LAST - TPM_CC_PP_FIRST + 1) + 7)/8]; 431
432 //*********************************************************************************
433 // Dictionary attack values
434 //*********************************************************************************
435 // These values are used for dictionary attack tracking and control.
436 UINT32 failedTries; // the current count of unexpired
437 // authorization failures
438
439 UINT32 maxTries; // number of unexpired authorization
440 | // failures before the TPM is in |
441 | // lockout |
442 | |
443 | UINT32 recoveryTime; // time between authorization failures |
444 | // before failedTries is decremented |
445 | |
446 | UINT32 lockoutRecovery; // time that must expire between |
447 | // authorization failures associated |
448 | // with lockoutAuth |
449 | |
450 | BOOL lockOutAuthEnabled; // TRUE if use of lockoutAuth is |
451 | // allowed |
452 | |
453 | //***************************************************************************** |
454 | // Orderly State |
455 | //***************************************************************************** |
456 | // The orderly state for current cycle |
457 | TPM_SU orderlyState; |
458 | |
459 | //***************************************************************************** |
460 | // Command audit values. |
461 | //***************************************************************************** |
462 | BYTE auditComands[((TPM_CC_LAST - TPM_CC_FIRST + 1) + 7) / 8]; |
463 | TPMI_ALG_HASH auditHashAlg; |
464 | UINT64 auditCounter; |
465 | |
466 | //***************************************************************************** |
467 | // Algorithm selection |
468 | //***************************************************************************** |
469 | // |
470 | // The 'algorithmSet' value indicates the collection of algorithms that are |
471 | // currently in used on the TPM. The interpretation of value is vendor dependent. |
472 | UINT32 algorithmSet; |
473 | |
474 | //***************************************************************************** |
475 | // Firmware version |
476 | //***************************************************************************** |
477 | // The firmwareV1 and firmwareV2 values are instanced in TimeStamp.c. This is |
478 | // a scheme used in development to allow determination of the linker build time |
479 | // of the TPM. An actual implementation would implement these values in a way that |
480 | // is consistent with vendor needs. The values are maintained in RAM for simplified |
481 | // access with a master version in NV. These values are modified in a |
482 | // vendor-specific way. |
483 | |
484 | // g_firmwareV1 contains the more significant 32-bits of the vendor version number. |
485 | // In the reference implementation, if this value is printed as a hex |
486 | // value, it will have the format of yyyymmdd |
487 | UINT32 firmwareV1; |
488 | |
489 | // g_firmwareV1 contains the less significant 32-bits of the vendor version number. |
490 | // In the reference implementation, if this value is printed as a hex |
491 | // value, it will have the format of 00 hh mm ss |
492 | UINT32 firmwareV2; |
493 | |
494 | } PERSISTENT_DATA; |
495 | extern PERSISTENT_DATA gp; |
The data in this structure is saved to NV on each TPM2_Shutdown(). | |
496 | typedef struct orderly_data |
497 | { |
498 |
499 //*****************************************************************************
500 // TIME
501 //*****************************************************************************
502
// Clock has two parts. One is the state save part and one is the NV part. The
// state save version is updated on each command. When the clock rolls over, the
// NV version is updated. When the TPM starts up, if the TPM was shutdown in and
// orderly way, then the sClock value is used to initialize the clock. If the
// TPM shutdown was not orderly, then the persistent value is used and the safe
// attribute is clear. 509
510 UINT64 clock; // The orderly version of clock
511 TPMI_YES_NO clockSafe; // Indicates if the clock value is
512 // safe.
513 //*********************************************************************************
514 // DRBG
515 //*********************************************************************************
516 #ifdef _DRBG_STATE_SAVE
517 // This is DRBG state data. This is saved each time the value of clock is
518 // updated.
519 DRBG_STATE drbgState;
520 #endif 521
522 } ORDERLY_DATA;
523 extern ORDERLY_DATA go;
This structure contains the data that is saved on Shutdown(STATE). and restored on Startup(STATE). The values are set to their default settings on any Startup(Clear). In other words the data is only persistent across TPM Resume.
If the comments associated with a parameter indicate a default reset value, the value is applied on each Startup(CLEAR).
524 typedef struct state_clear_data
525 {
526 //*****************************************************************************
527 // Hierarchy Control
528 //*****************************************************************************
BOOL shEnable; // default reset is SET
BOOL ehEnable; // default reset is SET
BOOL phEnableNV; // default reset is SET
TPMI_ALG_HASH platformAlg; // default reset is TPM_ALG_NULL
TPM2B_DIGEST platformPolicy; // default reset is an Empty Buffer
TPM2B_AUTH platformAuth; // default reset is an Empty Buffer 535
536 //*****************************************************************************
537 // PCR
538 //*****************************************************************************
539 // The set of PCR to be saved on Shutdown(STATE)
540 PCR_SAVE pcrSave; // default reset is 0...0 541
// This structure hold the authorization values for those PCR that have an
// update authorization.
// This implementation only supports a single group of PCR controlled by
// authorization. If more are required, then this structure would be changed to
// an array.
PCR_AUTHVALUE pcrAuthValues; 548
549 } STATE_CLEAR_DATA;
550 extern STATE_CLEAR_DATA gc;
This structure contains data is that is saved on Shutdown(STATE) and restored on the subsequent Startup(ANY). That is, the data is preserved across TPM Resume and TPM Restart.
If a default value is specified in the comments this value is applied on TPM Reset.
551 typedef struct state_reset_data
552 {
553 //*****************************************************************************
554 // Hierarchy Control
555 //*****************************************************************************
556 TPM2B_AUTH nullProof; // The proof value associated with
557 // the TPM_RH_NULL hierarchy. The
558 // default reset value is from the RNG.
559
560 TPM2B_SEED nullSeed; // The seed value for the TPM_RN_NULL
561 // hierarchy. The default reset value
562 // is from the RNG.
563
564 //*****************************************************************************
565 // Context
566 //*****************************************************************************
// The 'clearCount' counter is incremented each time the TPM successfully executes
// a TPM Resume. The counter is included in each saved context that has 'stClear'
// SET (including descendants of keys that have 'stClear' SET). This prevents these
// objects from being loaded after a TPM Resume.
// If 'clearCount' at its maximum value when the TPM receives a Shutdown(STATE),
// the TPM will return TPM_RC_RANGE and the TPM will only accept Shutdown(CLEAR).
UINT32 clearCount; // The default reset value is 0. 574
575 UINT64 objectContextID; // This is the context ID for a saved
576 // object context. The default reset
577 // value is 0.
578
579 CONTEXT_SLOT contextArray[MAX_ACTIVE_SESSIONS];
580 // This is the value from which the
581 // 'contextID' is derived. The
582 // default reset value is {0}.
583
584 CONTEXT_COUNTER contextCounter; // This array contains contains the
585 // values used to track the version
586 // numbers of saved contexts (see
587 // Session.c in for details). The
588 // default reset value is 0.
589
590 //*****************************************************************************
591 // Command Audit
592 //*****************************************************************************
593 // When an audited command completes, ExecuteCommand() checks the return
594 // value. If it is TPM_RC_SUCCESS, and the command is an audited command, the
595 // TPM will extend the cpHash and rpHash for the command to this value. If this
596 // digest was the Zero Digest before the cpHash was extended, the audit counter
597 // is incremented. 598
599 TPM2B_DIGEST commandAuditDigest; // This value is set to an Empty Digest 600 // by TPM2_GetCommandAuditDigest() or a
601 // TPM Reset.
602
603 //***************************************************************************** 604 // Boot counter
605 //*****************************************************************************
606
607 UINT32 restartCount; // This counter counts TPM Restarts. 608 // The default reset value is 0.
609
610 //*********************************************************************************
611 // PCR
612 //********************************************************************************* 613 // This counter increments whenever the PCR are updated. This counter is preserved 614 // across TPM Resume even though the PCR are not preserved. This is because
615 // sessions remain active across TPM Restart and the count value in the session 616 // is compared to this counter so this counter must have values that are unique 617 // as long as the sessions are active.
618 // NOTE: A platform-specific specification may designate that certain PCR changes 619 // do not increment this counter to increment.
620 UINT32 pcrCounter; // The default reset value is 0. 621
622 #ifdef TPM_ALG_ECC
623
624 //*****************************************************************************
625 // ECDAA
626 //***************************************************************************** 627 UINT64 commitCounter; // This counter increments each time 628 // TPM2_Commit() returns
629 // TPM_RC_SUCCESS. The default reset
630 // value is 0.
631
632 TPM2B_NONCE commitNonce; // This random value is used to compute 633 // the commit values. The default reset
634 // value is from the RNG.
635
636 // This implementation relies on the number of bits in g_commitArray being a 637 // power of 2 (8, 16, 32, 64, etc.) and no greater than 64K.
638 BYTE commitArray[16]; // The default reset value is {0}. 639
640 #endif //TPM_ALG_ECC
641
642 } STATE_RESET_DATA;
643 extern STATE_RESET_DATA gr;
This macro is used to ensure that a handle, session, or parameter number is only added if the response code is FMT1.
644 #define RcSafeAddToResult(r, v) \
645 ((r) + (((r) & RC_FMT1) ? (v) : 0))
This macro is used when a parameter is not otherwise referenced in a function. This macro is normally not used by itself but is paired with a pAssert() within a #ifdef pAssert. If pAssert is not defined, then a parameter might not otherwise be referenced. This macro uses the parameter from the perspective of the compiler so it doesn't complain.
#define UNREFERENCED(a) ((void)(a))
#if defined SESSION_PROCESS_C || defined GLOBAL_C || defined MANUFACTURE_C
From SessionProcess.c
The following arrays are used to save command sessions information so that the command handle/session buffer does not have to be preserved for the duration of the command. These arrays are indexed by the session index in accordance with the order of sessions in the session area of the command.
Array of the authorization session handles
extern TPM_HANDLE s_sessionHandles[MAX_SESSION_NUM];
Array of authorization session attributes
extern TPMA_SESSION s_attributes[MAX_SESSION_NUM];
Array of handles authorized by the corresponding authorization sessions; and if none, then TPM_RH_UNASSIGNED value is used
extern TPM_HANDLE s_associatedHandles[MAX_SESSION_NUM];
Array of nonces provided by the caller for the corresponding sessions
extern TPM2B_NONCE s_nonceCaller[MAX_SESSION_NUM];
Array of authorization values (HMAC's or passwords) for the corresponding sessions
extern TPM2B_AUTH s_inputAuthValues[MAX_SESSION_NUM];
Special value to indicate an undefined session index
#define UNDEFINED_INDEX (0xFFFF)
Index of the session used for encryption of a response parameter
extern UINT32 s_encryptSessionIndex;
Index of the session used for decryption of a command parameter
extern UINT32 s_decryptSessionIndex;
Index of a session used for audit
extern UINT32 s_auditSessionIndex;
The cpHash for an audit session
extern TPM2B_DIGEST s_cpHashForAudit;
The cpHash for command audit
#ifdef TPM_CC_GetCommandAuditDigest
extern TPM2B_DIGEST s_cpHashForCommandAudit; 660 #endif
Number of authorization sessions present in the command
661 extern UINT32 s_sessionNum;
Flag indicating if NV update is pending for the lockOutAuthEnabled or failedTries DA parameter
662 extern BOOL s_DAPendingOnNV; 663 #endif // SESSION_PROCESS_C
664 #if defined DA_C || defined GLOBAL_C || defined MANUFACTURE_C
From DA.c
This variable holds the accumulated time since the last time that failedTries was decremented. This value is in millisecond.
665 extern UINT64 s_selfHealTimer;
This variable holds the accumulated time that the lockoutAuth has been blocked.
666 | extern UINT64 | s_lockoutTimer; |
667 | #endif // DA_C | |
668 | #if defined NV_C || | defined GLOBAL_C |
From NV.c
List of pre-defined address of reserved data
extern UINT32 s_reservedAddr[NV_RESERVE_LAST];
List of pre-defined reserved data size in byte
extern UINT32 s_reservedSize[NV_RESERVE_LAST];
Size of data in RAM index buffer
extern UINT32 s_ramIndexSize;
Reserved RAM space for frequently updated NV Index. The data layout in ram buffer is {NV_handle(), size of data, data} for each NV index data stored in RAM
extern BYTE s_ramIndex[RAM_INDEX_SPACE];
Address of size of RAM index space in NV
extern UINT32 s_ramIndexSizeAddr;
Address of NV copy of RAM index space
extern UINT32 s_ramIndexAddr;
Address of maximum counter value; an auxiliary variable to implement NV counters
extern UINT32 s_maxCountAddr;
Beginning of NV dynamic area; starts right after the s_maxCountAddr and s_evictHandleMapAddr
variables
extern UINT32 s_evictNvStart;
Beginning of NV dynamic area; also the beginning of the predefined reserved data area.
extern UINT32 s_evictNvEnd;
NV availability is sampled as the start of each command and stored here so that its value remains consistent during the command execution
extern TPM_RC s_NvStatus; 679 #endif
680 #if defined OBJECT_C || defined GLOBAL_C
From Object.c
This type is the container for an object.
681 typedef struct
682 {
BOOL occupied;
ANY_OBJECT object;
} OBJECT_SLOT;
This is the memory that holds the loaded objects.
extern OBJECT_SLOT s_objects[MAX_LOADED_OBJECTS];
#endif // OBJECT_C
#if defined PCR_C || defined GLOBAL_C
From PCR.c
typedef struct
690 {
#ifdef TPM_ALG_SHA1
// SHA1 PCR
BYTE sha1Pcr[SHA1_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA256
// SHA256 PCR
BYTE sha256Pcr[SHA256_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA384
// SHA384 PCR
BYTE sha384Pcr[SHA384_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SHA512
// SHA512 PCR
BYTE sha512Pcr[SHA512_DIGEST_SIZE];
#endif
#ifdef TPM_ALG_SM3_256
// SHA256 PCR
BYTE sm3_256Pcr[SM3_256_DIGEST_SIZE];
#endif
} PCR;
typedef struct
713 {
714 unsigned int stateSave : 1; // if the PCR value should be 715 // saved in state save
716 unsigned int resetLocality : 5; // The locality that the PCR 717 // can be reset
718 unsigned int extendLocality : 5; // The locality that the PCR 719 // can be extend
720 } PCR_Attributes;
721 extern PCR s_pcrs[IMPLEMENTATION_PCR]; 722 #endif // PCR_C
723 #if defined SESSION_C || defined GLOBAL_C
From Session.c
Container for HMAC or policy session tracking information
724 typedef struct
725 {
726 BOOL occupied;
727 SESSION session; // session structure 728 } SESSION_SLOT;
729 extern SESSION_SLOT s_sessions[MAX_LOADED_SESSIONS];
The index in conextArray that has the value of the oldest saved session context. When no context is saved, this will have a value that is greater than or equal to MAX_ACTIVE_SESSIONS.
730 extern UINT32 s_oldestSavedSession;
The number of available session slot openings. When this is 1, a session can't be created or loaded if the GAP is maxed out. The exception is that the oldest saved session context can always be loaded (assuming that there is a space in memory to put it)
731 | extern int | s_freeSessionSlots; |
732 | #endif // SESSION_C | |
From Manufacture.c | ||
733 | extern BOOL | g_manufactured; |
734 | #if defined POWER_C | || defined GLOBAL_C |
From Power.c
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.
735 | extern BOOL | s_initialized; |
736 | #endif // POWER_C | |
737 | #if defined MEMORY_LIB_C | || defined GLOBAL_C |
The s_actionOutputBuffer should not be modifiable by the host system until the TPM has returned a response code. The s_actionOutputBuffer should not be accessible until response parameter encryption, if any, is complete.
738 extern UINT32 s_actionInputBuffer[1024]; // action input buffer 739 extern UINT32 s_actionOutputBuffer[1024]; // action output buffer 740 extern BYTE s_responseBuffer[MAX_RESPONSE_SIZE];// response buffer
741 #endif // MEMORY_LIB_C
From TPMFail.c
This value holds the address of the string containing the name of the function in which the failure occurred. This address value isn't useful for anything other than helping the vendor to know in which file the failure occurred.
742 | extern jmp_buf g_jumpBuffer; // | the jump buffer |
743 | extern BOOL g_inFailureMode; // | Indicates that the TPM is in failure mode |
744 | extern BOOL g_forceFailureMode; // | flag to force failure mode during test |
745 | #if defined TPM_FAIL_C || defined GLOBAL_C | || 1 |
746 | extern UINT32 s_failFunction; | |
747 | extern UINT32 s_failLine; // | the line in the file at which |
748 | // | the error was signaled |
749 | extern UINT32 s_failCode; // | the error code used |
750 | #endif // TPM_FAIL_C | |
751 | #endif // GLOBAL_H |
Root header file for building any TPM.lib code
1 | #ifndef | _TPM_H_ |
2 | #define | _TPM_H_ |
3 | #include | "bool.h" |
#include "Implementation.h"
#include "TPM_Types.h"
#include "swap.h"
7 #endif // _TPM_H_
#ifndef _SWAP_H
#define _SWAP_H
#include "Implementation.h"
#if NO_AUTO_ALIGN == YES || LITTLE_ENDIAN_TPM == YES
The aggregation macros for machines that do not allow unaligned access or for little-endian machines. Aggregate bytes into an UINT
#define BYTE_ARRAY_TO_UINT8(b) (UINT8)((b)[0])
#define BYTE_ARRAY_TO_UINT16(b) (UINT16)( ((b)[0] << 8) \ 7 + (b)[1])
8 #define BYTE_ARRAY_TO_UINT32(b) (UINT32)( ((b)[0] << 24) \ 9 + ((b)[1] << 16) \
10 + ((b)[2] << 8 ) \
11 + (b)[3])
12 #define BYTE_ARRAY_TO_UINT64(b) (UINT64)( ((UINT64)(b)[0] << 56) \ 13 + ((UINT64)(b)[1] << 48) \
14 + ((UINT64)(b)[2] << 40) \
15 + ((UINT64)(b)[3] << 32) \
16 + ((UINT64)(b)[4] << 24) \
17 + ((UINT64)(b)[5] << 16) \
18 + ((UINT64)(b)[6] << 8) \
19 + (UINT64)(b)[7])
Disaggregate a UINT into a byte array
#define UINT8_TO_BYTE_ARRAY(i, b) ((b)[0] = (BYTE)(i), i)
#define UINT16_TO_BYTE_ARRAY(i, b) ((b)[0] = (BYTE)((i) >> 8), \ 22 (b)[1] = (BYTE) (i), \
23 (i))
24 #define UINT32_TO_BYTE_ARRAY(i, b) ((b)[0] = (BYTE)((i) >> 24), \ 25 (b)[1] = (BYTE)((i) >> 16), \
26 (b)[2] = (BYTE)((i) >> 8), \
27 (b)[3] = (BYTE) (i), \
28 (i))
29 #define UINT64_TO_BYTE_ARRAY(i, b) ((b)[0] = (BYTE)((i) >> 56), \ 30 (b)[1] = (BYTE)((i) >> 48), \
31 (b)[2] = (BYTE)((i) >> 40), \
32 (b)[3] = (BYTE)((i) >> 32), \
33 (b)[4] = (BYTE)((i) >> 24), \
34 (b)[5] = (BYTE)((i) >> 16), \
35 (b)[6] = (BYTE)((i) >> 8), \
36 (b)[7] = (BYTE) (i), \
37 (i))
38 #else
the big-endian macros for machines that allow unaligned memory access Aggregate a byte array into a UINT
39 | #define | BYTE_ARRAY_TO_UINT8(b) | *((UINT8 | *)(b)) |
40 | #define | BYTE_ARRAY_TO_UINT16(b) | *((UINT16 | *)(b)) |
41 | #define | BYTE_ARRAY_TO_UINT32(b) | *((UINT32 | *)(b)) |
42 | #define | BYTE_ARRAY_TO_UINT64(b) | *((UINT64 | *)(b)) |
Disaggregate a UINT into a byte array
#define UINT8_TO_BYTE_ARRAY(i, b) (*((UINT8 *)(b)) = (i))
#define UINT16_TO_BYTE_ARRAY(i, b) (*((UINT16 *)(b)) = (i))
#define UINT32_TO_BYTE_ARRAY(i, b) (*((UINT32 *)(b)) = (i))
#define UINT64_TO_BYTE_ARRAY(i, b) (*((UINT64 *)(b)) = (i))
#endif // NO_AUTO_ALIGN == YES
48 #endif // _SWAP_H
#ifndef INTERNAL_ROUTINES_H
#define INTERNAL_ROUTINES_H
NULL definition
#ifndef NULL
#define NULL (0)
#endif
UNUSED_PARAMETER
#ifndef UNUSED_PARAMETER
#define UNUSED_PARAMETER(param) (void)(param);
#endif
Internal data definition
#include "Global.h"
#include "VendorString.h"
Error Reporting
#include "TpmError.h"
DRTM functions
#include "_TPM_Hash_Start_fp.h"
#include "_TPM_Hash_Data_fp.h"
#include "_TPM_Hash_End_fp.h"
Internal subsystem functions
#include "Object_fp.h"
#include "Entity_fp.h"
#include "Session_fp.h"
#include "Hierarchy_fp.h"
#include "NV_fp.h"
#include "PCR_fp.h"
#include "DA_fp.h"
#include "TpmFail_fp.h"
Internal support functions
#include "CommandCodeAttributes_fp.h"
#include "MemoryLib_fp.h"
#include "marshal_fp.h"
#include "Time_fp.h"
#include "Locality_fp.h"
#include "PP_fp.h"
#include "CommandAudit_fp.h"
#include "Manufacture_fp.h"
#include "Power_fp.h"
#include "Handle_fp.h"
#include "Commands_fp.h"
#include "AlgorithmCap_fp.h"
#include "PropertyCap_fp.h"
#include "Bits_fp.h"
Internal crypto functions
#include "Ticket_fp.h"
#include "CryptUtil_fp.h"
#include "CryptSelfTest_fp.h"
40 #endif
This file contains the build switches. This contains switches for multiple versions of the crypto-library so some may not apply to your environment.
#ifndef _TPM_BUILD_SWITCHES_H
#define _TPM_BUILD_SWITCHES_H
#define SIMULATION
#define FIPS_COMPLIANT
Define the alignment macro appropriate for the build environment For MS C compiler
#define ALIGN_TO(boundary) declspec(align(boundary))
For ISO 9899:2011
// #define ALIGN_TO(boundary) _Alignas(boundary)
This switch enables the RNG state save and restore
#undef _DRBG_STATE_SAVE
#define _DRBG_STATE_SAVE // Comment this out if no state save is wanted
Set the alignment size for the crypto. It would be nice to set this according to macros automatically defined by the build environment, but that doesn't seem possible because there isn't any simple set for that. So, this is just a plugged value. Your compiler should complain if this alignment isn't possible.
NOTE: this value can be set at the command line or just plugged in here.
9 | #ifdef CRYPTO_ALIGN_16 | ||
10 | # define CRYPTO_ALIGNMENT | 16 | |
11 | #elif defined CRYPTO_ALIGN_8 | ||
12 | # define CRYPTO_ALIGNMENT | 8 | |
13 | #eliF defined CRYPTO_ALIGN_2 | ||
14 | # define CRYPTO_ALIGNMENT | 2 | |
15 | #elif defined CRTYPO_ALIGN_1 | ||
16 | # define CRYPTO_ALIGNMENT | 1 | |
17 | #else | ||
18 | # define CRYPTO_ALIGNMENT | 4 | // For 32-bit builds |
#endif
#define CRYPTO_ALIGNED ALIGN_TO(CRYPTO_ALIGNMENT)
This macro is used to handle LIB_EXPORT of function and variable names in lieu of a .def file
#define LIB_EXPORT declspec(dllexport)
// #define LIB_EXPORT
For import of a variable
#define LIB_IMPORT declspec(dllimport)
//#define LIB_IMPORT
This is defined to indicate a function that does not return. This is used in static code anlaysis.
#define _No_Return_ declspec(noreturn)
//#define _No_Return_
#ifdef SELF_TEST
#pragma comment(lib, "algorithmtests.lib")
#endif
The switches in this group can only be enabled when running a simulation
#ifdef SIMULATION
# define RSA_KEY_CACHE
# define TPM_RNG_FOR_DEBUG
#else
# undef RSA_KEY_CACHE
# undef TPM_RNG_FOR_DEBUG
#endif // SIMULATION
#define INLINE inline
#endif // _TPM_BUILD_SWITCHES_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.
#define MANUFACTURER "MSFT"
The following #if macro may be deleted after a proper MANUFACTURER is provided.
#ifndef MANUFACTURER
#error MANUFACTURER is not provided. \
Please modify include\VendorString.h to provide a specific \
manufacturer name.
#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 appropriately.
#define VENDOR_STRING_1 "xCG "
#define VENDOR_STRING_2 "fTPM"
// #define VENDOR_STRING_3
// #define VENDOR_STRING_4
The following #if macro may be deleted after a proper VENDOR_STRING_1 is provided.
#ifndef VENDOR_STRING_1
#error VENDOR_STRING_1 is not provided. \
Please modify include\VendorString.h to provide a vednor specific \
string.
#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.
#define FIRMWARE_V1 (0x20140504)
the less significant 32-bits of a vendor-specific value indicating the version of the firmware
#define FIRMWARE_V2 (0x00200136)
The following #if macro may be deleted after a proper FIRMWARE_V1 is provided.
#ifndef FIRMWARE_V1
#error FIRMWARE_V1 is not provided. \
Please modify include\VendorString.h to provide a vendor specific firmware \
version
#endif
25 #endif
In the reference implementation, a program that uses TPM 2.0 Part 3 as input automatically generates the command dispatch code. The function prototype header file (CommandDispatcher_fp.h) is shown here.
CommandDispatcher() performs the following operations:
unmarshals command parameters from the input buffer;
invokes the function that performs the command actions;
marshals the returned handles, if any; and
marshals the returned parameters, if any, into the output buffer putting in the parameterSize field if authorization sessions are present.
#ifndef _COMMANDDISPATCHER_FP_H_
#define _COMMANDDISPATCHER_FP_H_
TPM_RC
CommandDispatcher(
TPMI_ST_COMMAND_TAG tag, // IN: Input command tag
TPM_CC commandCode, // IN: Command code
INT32 *parmBufferSize, // IN: size of parameter buffer
BYTE *parmBufferStart, // IN: pointer to start of parameter buffer
TPM_HANDLE handles[], // IN: handle array
UINT32 *responseHandleSize,// OUT: size of handle buffer in response
UINT32 *respParmSize // OUT: size of parameter buffer in response 12 );
13 #endif // _COMMANDDISPATCHER_FP_H_
This file contains the entry function ExecuteCommand() which provides the main control flow for TPM command execution.
#include "InternalRoutines.h"
#include "HandleProcess_fp.h"
#include "SessionProcess_fp.h"
#include "CommandDispatcher_fp.h"
Uncomment this next #include if doing static command/response buffer sizing
// #include "CommandResponseSizes_fp.h"
The function performs the following steps.
Parses the command header from input buffer.
Calls ParseHandleBuffer() to parse the handle area of the command.
Validates that each of the handles references a loaded entity.
Calls ParseSessionBuffer() () to:
unmarshal and parse the session area;
check the authorizations; and
when necessary, decrypt a parameter.
Calls CommandDispatcher() to:
unmarshal the command parameters from the command buffer;
call the routine that performs the command actions; and
marshal the responses into the response buffer.
If any error occurs in any of the steps above create the error response and return.
Calls BuildResponseSession() to:
when necessary, encrypt a parameter
build the response authorization sessions
update the audit sessions and nonces
Assembles handle, parameter and session buffers for response and return.
LIB_EXPORT void
ExecuteCommand(
unsigned int requestSize, // IN: command buffer size
unsigned char *request, // IN: command buffer
unsigned int *responseSize, // OUT: response buffer size
unsigned char **response // OUT: response buffer 12 )
13 {
// Command local variables
TPM_ST tag; // these first three variables are the
UINT32 commandSize;
TPM_CC commandCode = 0; 18
BYTE *parmBufferStart; // pointer to the first byte of an
// optional parameter buffer
21
22 UINT32 parmBufferSize = 0;// number of bytes in parameter area 23
UINT32 handleNum = 0; // number of handles unmarshaled into
// the handles array
26
TPM_HANDLE handles[MAX_HANDLE_NUM];// array to hold handles in the
// command. Only handles in the handle
// area are stored here, not handles
// passed as parameters.
31
// Response local variables
TPM_RC result; // return code for the command 34
35 TPM_ST resTag; // tag for the response 36
UINT32 resHandleSize = 0; // size of the handle area in the
// response. This is needed so that the
// handle area can be skipped when
// generating the rpHash.
41
UINT32 resParmSize = 0; // the size of the response parameters
// These values go in the rpHash.
44
45 UINT32 resAuthSize = 0; // size of authorization area in the
46 // response
47
INT32 size; // remaining data to be unmarshaled
// or remaining space in the marshaling
// buffer
51
BYTE *buffer; // pointer into the buffer being used
// for marshaling or unmarshaling
54
55 UINT32 i; // local temp 56
// This next function call is used in development to size the command and response
// buffers. The values printed are the sizes of the internal structures and
// not the sizes of the canonical forms of the command response structures. Also,
// the sizes do not include the tag, commandCode, requestSize, or the authorization
// fields.
//CommandResponseSizes(); 63
// Set flags for NV access state. This should happen before any other
// operation that may require a NV write. Note, that this needs to be done
// even when in failure mode. Otherwise, g_updateNV would stay SET while in
// Failure mode and the NB would be written on each call.
g_updateNV = FALSE;
g_clearOrderly = FALSE; 70
// As of Sept 25, 2013, the failure mode handling has been incorporated in the
// reference code. This implementation requires that the system support
// setjmp/longjmp. This code is put here because of the complexity being
// added to the platform and simulator code to deal with all the variations
// of errors.
if(g_inFailureMode)
77 {
// Do failure mode processing
TpmFailureMode (requestSize, request, responseSize, response);
return;
81 }
82 if(setjmp(g_jumpBuffer) != 0) 83 {
// Get here if we got a longjump putting us into failure mode
g_inFailureMode = TRUE;
result = TPM_RC_FAILURE;
goto Fail; 88 }
89
// Assume that everything is going to work.
result = TPM_RC_SUCCESS; 92
// Query platform to get the NV state. The result state is saved internally
// and will be reported by NvIsAvailable(). The reference code requires that
// accessibility of NV does not change during the execution of a command.
// Specifically, if NV is available when the command execution starts and then
// is not available later when it is necessary to write to NV, then the TPM
// will go into failure mode.
NvCheckState(); 100
// Due to the limitations of the simulation, TPM clock must be explicitly
// synchronized with the system clock whenever a command is received.
// This function call is not necessary in a hardware TPM. However, taking
// a snapshot of the hardware timer at the beginning of the command allows
// the time value to be consistent for the duration of the command execution.
TimeUpdateToCurrent(); 107
// Any command through this function will unceremoniously end the
// _TPM_Hash_Data/_TPM_Hash_End sequence.
if(g_DRTMHandle != TPM_RH_UNASSIGNED)
ObjectTerminateEvent();
112
// Get command buffer size and command buffer.
size = requestSize;
buffer = request; 116
// Parse command header: tag, commandSize and commandCode.
// First parse the tag. The unmarshaling routine will validate
// that it is either TPM_ST_SESSIONS or TPM_ST_NO_SESSIONS.
result = TPMI_ST_COMMAND_TAG_Unmarshal(&tag, &buffer, &size);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 123
// Unmarshal the commandSize indicator.
result = UINT32_Unmarshal(&commandSize, &buffer, &size);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 128
// On a TPM that receives bytes on a port, the number of bytes that were
// received on that port is requestSize it must be identical to commandSize.
// In addition, commandSize must not be larger than MAX_COMMAND_SIZE allowed
// by the implementation. The check against MAX_COMMAND_SIZE may be redundant
// as the input processing (the function that receives the command bytes and
// places them in the input buffer) would likely have the input truncated when
// it reaches MAX_COMMAND_SIZE, and requestSize would not equal commandSize.
if(commandSize != requestSize || commandSize > MAX_COMMAND_SIZE)
137 {
result = TPM_RC_COMMAND_SIZE;
goto Cleanup;
140 }
141
// Unmarshal the command code.
result = TPM_CC_Unmarshal(&commandCode, &buffer, &size);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 146
// Check to see if the command is implemented.
if(!CommandIsImplemented(commandCode))
149 {
result = TPM_RC_COMMAND_CODE;
goto Cleanup;
152 }
153
#if FIELD_UPGRADE_IMPLEMENTED == YES
// If the TPM is in FUM, then the only allowed command is
// TPM_CC_FieldUpgradeData.
if(IsFieldUgradeMode() && (commandCode != TPM_CC_FieldUpgradeData))
158 {
result = TPM_RC_UPGRADE;
goto Cleanup;
161 }
else
#endif
// Excepting FUM, the TPM only accepts TPM2_Startup() after
// _TPM_Init. After getting a TPM2_Startup(), TPM2_Startup()
// is no longer allowed.
if(( !TPMIsStarted() && commandCode != TPM_CC_Startup)
|| (TPMIsStarted() && commandCode == TPM_CC_Startup))
169 {
result = TPM_RC_INITIALIZE;
goto Cleanup;
172 }
173
// Start regular command process.
// Parse Handle buffer.
result = ParseHandleBuffer(commandCode, &buffer, &size, handles, &handleNum);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 179
// Number of handles retrieved from handle area should be less than
// MAX_HANDLE_NUM.
pAssert(handleNum <= MAX_HANDLE_NUM); 183
// All handles in the handle area are required to reference TPM-resident
// entities.
for(i = 0; i < handleNum; i++)
187 {
result = EntityGetLoadStatus(&handles[i], commandCode);
if(result != TPM_RC_SUCCESS)
190 {
if(result == TPM_RC_REFERENCE_H0)
result = result + i;
else
result = RcSafeAddToResult(result, TPM_RC_H + g_rcIndex[i]);
goto Cleanup;
196 }
197 }
198
// Authorization session handling for the command.
if(tag == TPM_ST_SESSIONS)
201 {
BYTE *sessionBufferStart;// address of the session area first byte
// in the input buffer
204
205 UINT32 authorizationSize; // number of bytes in the session area 206
// Find out session buffer size.
result = UINT32_Unmarshal(&authorizationSize, &buffer, &size);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 211
// Perform sanity check on the unmarshaled value. If it is smaller than
// the smallest possible session or larger than the remaining size of
// the command, then it is an error. NOTE: This check could pass but the
// session size could still be wrong. That will be determined after the
// sessions are unmarshaled.
if( authorizationSize < 9
|| authorizationSize > (UINT32) size)
219 {
result = TPM_RC_SIZE;
goto Cleanup;
222 }
223
// The sessions, if any, follows authorizationSize.
sessionBufferStart = buffer; 226
// The parameters follow the session area.
parmBufferStart = sessionBufferStart + authorizationSize; 229
// Any data left over after removing the authorization sessions is
// parameter data. If the command does not have parameters, then an
// error will be returned if the remaining size is not zero. This is
// checked later.
parmBufferSize = size - authorizationSize; 235
// The actions of ParseSessionBuffer() are described in the introduction.
result = ParseSessionBuffer(commandCode,
handleNum,
handles,
sessionBufferStart,
authorizationSize,
parmBufferStart,
parmBufferSize);
if(result != TPM_RC_SUCCESS)
goto Cleanup;
246 }
247 else
248 {
// Whatever remains in the input buffer is used for the parameters of the
// command.
parmBufferStart = buffer;
parmBufferSize = size; 253
// The command has no authorization sessions.
// If the command requires authorizations, then CheckAuthNoSession() will
// return an error.
result = CheckAuthNoSession(commandCode, handleNum, handles,
parmBufferStart, parmBufferSize);
if(result != TPM_RC_SUCCESS)
goto Cleanup;
261 }
262
// CommandDispatcher returns a response handle buffer and a response parameter
// buffer if it succeeds. It will also set the parameterSize field in the
// buffer if the tag is TPM_RC_SESSIONS.
result = CommandDispatcher(tag,
commandCode,
(INT32 *) &parmBufferSize,
parmBufferStart,
handles,
&resHandleSize,
&resParmSize);
if(result != TPM_RC_SUCCESS)
goto Cleanup; 275
// Build the session area at the end of the parameter area.
BuildResponseSession(tag,
commandCode,
resHandleSize,
resParmSize,
&resAuthSize);
282
Cleanup:
// This implementation loads an "evict" object to a transient object slot in
// RAM whenever an "evict" object handle is used in a command so that the
// access to any object is the same. These temporary objects need to be
// cleared from RAM whether the command succeeds or fails.
ObjectCleanupEvict(); 289
Fail:
// The response will contain at least a response header.
*responseSize = sizeof(TPM_ST) + sizeof(UINT32) + sizeof(TPM_RC); 293
// If the command completed successfully, then build the rest of the response.
if(result == TPM_RC_SUCCESS)
296 {
// Outgoing tag will be the same as the incoming tag.
resTag = tag;
// The overall response will include the handles, parameters,
// and authorizations.
*responseSize += resHandleSize + resParmSize + resAuthSize; 302
// Adding parameter size field.
if(tag == TPM_ST_SESSIONS)
*responseSize += sizeof(UINT32); 306
if( g_clearOrderly == TRUE
&& gp.orderlyState != SHUTDOWN_NONE)
309 {
310 | gp.orderlyState = SHUTDOWN_NONE; | |
311 | NvWriteReserved(NV_ORDERLY, &gp.orderlyState); | |
312 | g_updateNV = TRUE; | |
313 | } | |
314 | } | |
315 | else | |
316 | { | |
317 | // The command failed. | |
318 | // If this was a failure due to a bad command tag, then need to return | |
319 | // a TPM 1.2 compatible response | |
320 | if(result == TPM_RC_BAD_TAG) | |
321 | resTag = TPM_ST_RSP_COMMAND; | |
322 | else | |
323 | // return 2.0 compatible response | |
324 | resTag = TPM_ST_NO_SESSIONS; | |
325 | } | |
326 | // Try to commit all the writes to NV if any NV write happened during this | |
327 | // command execution. This check should be made for both succeeded and failed | |
328 | // commands, because a failed one may trigger a NV write in DA logic as well. | |
329 | // This is the only place in the command execution path that may call the NV | |
330 | // commit. If the NV commit fails, the TPM should be put in failure mode. | |
331 | if(g_updateNV && !g_inFailureMode) | |
332 | { | |
333 | g_updateNV = FALSE; | |
334 | if(!NvCommit()) | |
335 | FAIL(FATAL_ERROR_INTERNAL); | |
336 | } | |
337 | ||
338 | // Marshal the response header. | |
339 | buffer = MemoryGetResponseBuffer(commandCode); | |
340 | TPM_ST_Marshal(&resTag, &buffer, NULL); | |
341 | UINT32_Marshal((UINT32 *)responseSize, &buffer, NULL); | |
342 | pAssert(*responseSize <= MAX_RESPONSE_SIZE); | |
343 | TPM_RC_Marshal(&result, &buffer, NULL); | |
344 | ||
345 | *response = MemoryGetResponseBuffer(commandCode); | |
346 | ||
347 | // Clear unused bit in response buffer. | |
348 | MemorySet(*response + *responseSize, 0, MAX_RESPONSE_SIZE - *responseSize); | |
349 | ||
350 | return; | |
351 | } |
In the reference implementation, the routine for unmarshaling the command handles is automatically generated from TPM 2.0 Part 3 command tables. The prototype header file (HandleProcess_fp.h) is shown here.
1 | #ifndef _HANDLEPROCESS_FP_H_ | ||
2 | #define _HANDLEPROCESS_FP_H_ | ||
3 | TPM_RC | ||
4 | ParseHandleBuffer( | ||
5 | TPM_CC commandCode, | // | IN: Command being processed |
6 | BYTE **handleBufferStart, | // | IN/OUT: command buffer where handles |
7 | // | are located. Updated as handles | |
8 | // | are unmarshaled | |
9 | INT32 *bufferRemainingSize, | // | IN/OUT: indicates the amount of data |
10 | // | left in the command buffer. | |
11 | // | Updated as handles are unmarshaled | |
12 | TPM_HANDLE handles[], | // | OUT: Array that receives the handles |
13 | UINT32 *handleCount | // | OUT: Receives the count of handles |
14 | ); | ||
15 | #endif // _HANDLEPROCESS_FP_H_ |
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.
Includes and Data Definitions
#define SESSION_PROCESS_C
#include "InternalRoutines.h"
#include "SessionProcess_fp.h"
#include "Platform.h"
Authorization Support Functions
This function indicates if a handle is exempted from DA logic. A handle is exempted if it is
a primary seed handle,
an object with noDA bit SET,
an NV Index with TPMA_NV_NO_DA bit SET, or
a PCR handle.
Return Value | Meaning |
TRUE | handle is exempted from DA logic |
FALSE | handle is not exempted from DA logic |
BOOL
IsDAExempted(
TPM_HANDLE handle // IN: entity handle 8 )
9 {
10 BOOL result = FALSE; 11
12 switch(HandleGetType(handle)) 13 {
case TPM_HT_PERMANENT:
// All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
// DA protection.
result = (handle != TPM_RH_LOCKOUT);
break;
19
// When this function is called, a persistent object will have been loaded
// into an object slot and assigned a transient handle.
case TPM_HT_TRANSIENT:
23 {
OBJECT *object;
object = ObjectGet(handle);
result = (object->publicArea.objectAttributes.noDA == SET);
break;
28 }
29 case TPM_HT_NV_INDEX:
30 {
31 NV_INDEX nvIndex;
32 | NvGetIndexInfo(handle, &nvIndex); | |
33 | result = (nvIndex.publicArea.attributes.TPMA_NV_NO_DA == SET); | |
34 | break; | |
35 | } | |
36 | case TPM_HT_PCR: | |
37 | // PCRs are always exempted from DA. | |
38 | result = TRUE; | |
39 | break; | |
40 | default: | |
41 | break; | |
42 | } | |
43 | return result; | |
44 | } |
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.
Error Returns | Meaning |
TPM_RC_AUTH_FAIL | authorization failure that caused DA lockout to increment |
TPM_RC_BAD_AUTH | authorization failure did not cause DA lockout to increment |
static TPM_RC
IncrementLockout(
UINT32 sessionIndex 48 )
49 {
TPM_HANDLE handle = s_associatedHandles[sessionIndex];
TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
TPM_RC result;
SESSION *session = NULL; 54
// Don't increment lockout unless the handle associated with the session
// is DA protected or the session is bound to a DA protected entity.
if(sessionHandle == TPM_RS_PW) 58 {
if(IsDAExempted(handle))
return TPM_RC_BAD_AUTH; 61
62 }
63 else
64 {
session = SessionGet(sessionHandle);
// If the session is bound to lockout, then use that as the relevant
// handle. This means that an auth failure with a bound session
// bound to lockoutAuth will take precedence over any other
// lockout check
if(session->attributes.isLockoutBound == SET)
handle = TPM_RH_LOCKOUT; 72
if( session->attributes.isDaBound == CLEAR
&& IsDAExempted(handle)
75 )
// If the handle was changed to TPM_RH_LOCKOUT, this will not return
// TPM_RC_BAD_AUTH
return TPM_RC_BAD_AUTH; 79
80 }
81
82 if(handle == TPM_RH_LOCKOUT)
83 | { | |
84 | pAssert(gp.lockOutAuthEnabled); | |
85 | gp.lockOutAuthEnabled = FALSE; | |
86 | // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since | |
87 | // the lockout auth will be reset at startup. | |
88 | if(gp.lockoutRecovery != 0) | |
89 | { | |
90 | result = NvIsAvailable(); | |
91 | if(result != TPM_RC_SUCCESS) | |
92 | { | |
93 | // No NV access for now. Put the TPM in pending mode. | |
94 | s_DAPendingOnNV = TRUE; | |
95 | } | |
96 | else | |
97 | { | |
98 | // Update NV. | |
99 | NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); | |
100 | g_updateNV = TRUE; | |
101 | } | |
102 | } | |
103 | } | |
104 | else | |
105 | { | |
106 | if(gp.recoveryTime != 0) | |
107 | { | |
108 | gp.failedTries++; | |
109 | result = NvIsAvailable(); | |
110 | if(result != TPM_RC_SUCCESS) | |
111 | { | |
112 | // No NV access for now. Put the TPM in pending mode. | |
113 | s_DAPendingOnNV = TRUE; | |
114 | } | |
115 | else | |
116 | { | |
117 | // Record changes to NV. | |
118 | NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries); | |
119 | g_updateNV = TRUE; | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | // Register a DA failure and reset the timers. | |
125 | DARegisterFailure(handle); | |
126 | ||
127 | return TPM_RC_AUTH_FAIL; | |
128 | } |
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.
Return Value | Meaning |
TRUE | handle points to the session start entity |
FALSE | handle does not point to the session start entity |
static BOOL
IsSessionBindEntity(
TPM_HANDLE associatedHandle, // IN: handle to be authorized
SESSION *session // IN: associated session
133 | ) | ||
134 | { | ||
135 | TPM2B_NAME | entity; // The bind value for the e | |
136 | |||
137 | // If the session is not bound, return FALSE. | ||
138 | if(!session->attributes.isBound) | ||
139 | return FALSE; | ||
140 | |||
141 | // Compute the bind value for the entity. | ||
142 | SessionComputeBoundEntity(associatedHandle, &entity); | ||
143 | |||
144 | // Compare to the bind value in the session. | ||
145 | session->attributes.requestWasBound = | ||
146 | Memory2BEqual(&entity.b, &session->u1.boundEntity.b); | ||
147 | return session->attributes.requestWasBound; | ||
148 | } |
ntity
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
Return Value | Meaning |
TRUE | policy session is required |
FALSE | policy session is not required |
static BOOL
IsPolicySessionRequired(
TPM_CC commandCode, // IN: command code
UINT32 sessionIndex // IN: session index
153 )
154 {
AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex);
TPM_HT type = HandleGetType(s_associatedHandles[sessionIndex]); 157
if(role == AUTH_DUP)
return TRUE; 160
161 if(role == AUTH_ADMIN)
162 {
163 if(type == TPM_HT_TRANSIENT)
164 {
165 OBJECT *object = ObjectGet(s_associatedHandles[sessionIndex]); 166
if(object->publicArea.objectAttributes.adminWithPolicy == CLEAR)
return FALSE;
169 }
170 return TRUE;
171 }
172
173 | if(type == TPM_HT_PCR) | |
174 | { | |
175 | if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex])) | |
176 | { | |
177 | TPM2B_DIGEST policy; | |
178 | TPMI_ALG_HASH policyAlg; | |
179 | policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], | |
180 | &policy); | |
181 | if(policyAlg != TPM_ALG_NULL) | |
182 | return TRUE; | |
183 | } | |
184 | } | |
185 | return FALSE; | |
186 | } |
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 auth, 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.
Return Value | Meaning |
TRUE | authValue is available |
FALSE | authValue is not available |
static BOOL
IsAuthValueAvailable(
TPM_HANDLE handle, // IN: handle of entity
TPM_CC commandCode, // IN: commandCode
UINT32 sessionIndex // IN: session index
192 )
193 {
BOOL result = FALSE;
// If a policy session is required, the entity can not be authorized by
// authValue. However, at this point, the policy session requirement should
// already have been checked.
pAssert(!IsPolicySessionRequired(commandCode, sessionIndex)); 199
200 switch(HandleGetType(handle))
201 {
case TPM_HT_PERMANENT:
switch(handle)
204 {
// At this point hierarchy availability has already been
// checked so primary seed handles are always available here
case TPM_RH_OWNER:
case TPM_RH_ENDORSEMENT:
case TPM_RH_PLATFORM:
#ifdef VENDOR_PERMANENT
// This vendor defined handle associated with the
// manufacturer's shared secret
case VENDOR_PERMANENT:
#endif
// NullAuth is always available.
case TPM_RH_NULL:
// At the point when authValue availability is checked, control
// path has already passed the DA check so LockOut auth is
// always available here
case TPM_RH_LOCKOUT:
221 | ||
222 | result = TRUE; | |
223 | break; | |
224 | default: | |
225 | // Otherwise authValue is not available. | |
226 | break; | |
227 | } | |
228 | break; | |
229 | case TPM_HT_TRANSIENT: | |
230 | // A persistent object has already been loaded and the internal | |
231 | // handle changed. | |
232 | { | |
233 | OBJECT *object; | |
234 | object = ObjectGet(handle); | |
235 | ||
236 | // authValue is always available for a sequence object. | |
237 | if(ObjectIsSequence(object)) | |
238 | { | |
239 | result = TRUE; | |
240 | break; | |
241 | } | |
242 | // authValue is available for an object if it has its sensitive | |
243 | // portion loaded and | |
244 | // 1. userWithAuth bit is SET, or | |
245 | // 2. ADMIN role is required | |
246 | if( object->attributes.publicOnly == CLEAR | |
247 | && (object->publicArea.objectAttributes.userWithAuth == SET | |
248 | || (CommandAuthRole(commandCode, sessionIndex) == AUTH_ADMIN | |
249 | && object->publicArea.objectAttributes.adminWithPolicy | |
250 | == CLEAR))) | |
251 | result = TRUE; | |
252 | } | |
253 | break; | |
254 | case TPM_HT_NV_INDEX: | |
255 | // NV Index. | |
256 | { | |
257 | NV_INDEX nvIndex; | |
258 | NvGetIndexInfo(handle, &nvIndex); | |
259 | if(IsWriteOperation(commandCode)) | |
260 | { | |
261 | if (nvIndex.publicArea.attributes.TPMA_NV_AUTHWRITE == SET) | |
262 | result = TRUE; | |
263 | ||
264 | } | |
265 | else | |
266 | { | |
267 | if (nvIndex.publicArea.attributes.TPMA_NV_AUTHREAD == SET) | |
268 | result = TRUE; | |
269 | } | |
270 | } | |
271 | break; | |
272 | case TPM_HT_PCR: | |
273 | // PCR handle. | |
274 | // authValue is always allowed for PCR | |
275 | result = TRUE; | |
276 | break; | |
277 | default: | |
278 | // Otherwise, authValue is not available | |
279 | break; | |
280 | } | |
281 | return result; | |
282 | } |
This function indicates if an authPolicy is available and allowed.
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.
Return Value | Meaning |
TRUE | authPolicy is available |
FALSE | authPolicy is not available |
static BOOL
IsAuthPolicyAvailable(
TPM_HANDLE handle, // IN: handle of entity
TPM_CC commandCode, // IN: commandCode
UINT32 sessionIndex // IN: session index
288 )
289 {
BOOL result = FALSE;
switch(HandleGetType(handle))
292 {
case TPM_HT_PERMANENT:
switch(handle)
295 {
// At this point hierarchy availability has already been checked.
case TPM_RH_OWNER:
if (gp.ownerPolicy.t.size != 0)
result = TRUE;
break;
301
case TPM_RH_ENDORSEMENT:
if (gp.endorsementPolicy.t.size != 0)
result = TRUE;
break;
306
case TPM_RH_PLATFORM:
if (gc.platformPolicy.t.size != 0)
result = TRUE;
break;
case TPM_RH_LOCKOUT:
if(gp.lockoutPolicy.t.size != 0)
result = TRUE;
break;
default:
break;
317 }
break;
case TPM_HT_TRANSIENT:
320 {
// Object handle.
// An evict object would already have been loaded and given a
// transient object handle by this point.
OBJECT *object = ObjectGet(handle);
// Policy authorization is not available for an object with only
// public portion loaded.
if(object->attributes.publicOnly == CLEAR)
328 {
// Policy authorization is always available for an object but
// is never available for a sequence.
if(!ObjectIsSequence(object))
result = TRUE;
333 }
334 break;
335 | } | |
336 | case TPM_HT_NV_INDEX: | |
337 | // An NV Index. | |
338 | { | |
339 | NV_INDEX nvIndex; | |
340 | NvGetIndexInfo(handle, &nvIndex); | |
341 | // If the policy size is not zero, check if policy can be used. | |
342 | if(nvIndex.publicArea.authPolicy.t.size != 0) | |
343 | { | |
344 | // If policy session is required for this handle, always | |
345 | // uses policy regardless of the attributes bit setting | |
346 | if(IsPolicySessionRequired(commandCode, sessionIndex)) | |
347 | result = TRUE; | |
348 | // Otherwise, the presence of the policy depends on the NV | |
349 | // attributes. | |
350 | else if(IsWriteOperation(commandCode)) | |
351 | { | |
352 | if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYWRITE | |
353 | == SET) | |
354 | result = TRUE; | |
355 | } | |
356 | else | |
357 | { | |
358 | if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYREAD | |
359 | == SET) | |
360 | result = TRUE; | |
361 | } | |
362 | } | |
363 | } | |
364 | break; | |
365 | case TPM_HT_PCR: | |
366 | // PCR handle. | |
367 | if(PCRPolicyIsAvailable(handle)) | |
368 | result = TRUE; | |
369 | break; | |
370 | default: | |
371 | break; | |
372 | } | |
373 | return result; | |
374 | } |
This function computes the cpHash as defined in Part 2 and described in Part 1.
static void
ComputeCpHash(
377 | TPMI_ALG_HASH | hashAlg, | // | IN: hash algorithm | ||
378 | TPM_CC | commandCode, | // | IN: command code | ||
379 | UINT32 | handleNum, | // | IN: number of handle | ||
380 | TPM_HANDLE | handles[], | // | IN: array of handle | ||
381 | UINT32 | parmBufferSize, | // | IN: size of input parameter | area | |
382 | BYTE | *parmBuffer, | // | IN: input parameter area | ||
383 | TPM2B_DIGEST | *cpHash, | // | OUT: cpHash | ||
384 | TPM2B_DIGEST | *nameHash | // | OUT: name hash of command | ||
385 | ) | |||||
386 | { | |||||
387 | UINT32 | i; | ||||
388 | HASH_STATE | hashState; | ||||
389 | TPM2B_NAME | name; | ||||
390 |
391 | // cpHash = hash(commandCode [ || authName1 | ||
392 | // [ || authName2 | ||
393 | // [ || authName 3 ]]] | ||
394 | // [ || parameters]) | ||
395 | // A cpHash can contain just a commandCode only if the lone session | is | |
396 | // an audit session. | ||
397 | |||
398 | // Start cpHash. | ||
399 | cpHash->t.size = CryptStartHash(hashAlg, &hashState); | ||
400 | |||
401 | // Add commandCode. | ||
402 | CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode); | ||
403 | |||
404 | // Add authNames for each of the handles. | ||
405 | for(i = 0; i < handleNum; i++) | ||
406 | { | ||
407 | name.t.size = EntityGetName(handles[i], &name.t.name); | ||
408 | CryptUpdateDigest2B(&hashState, &name.b); | ||
409 | } | ||
410 | |||
411 | // Add the parameters. | ||
412 | CryptUpdateDigest(&hashState, parmBufferSize, parmBuffer); | ||
413 | |||
414 | // Complete the hash. | ||
415 | CryptCompleteHash2B(&hashState, &cpHash->b); | ||
416 | |||
417 | // If the nameHash is needed, compute it here. | ||
418 | if(nameHash != NULL) | ||
419 | { | ||
420 | // Start name hash. hashState may be reused. | ||
421 | nameHash->t.size = CryptStartHash(hashAlg, &hashState); | ||
422 | |||
423 | // Adding names. | ||
424 | for(i = 0; i < handleNum; i++) | ||
425 | { | ||
426 | name.t.size = EntityGetName(handles[i], &name.t.name); | ||
427 | CryptUpdateDigest2B(&hashState, &name.b); | ||
428 | } | ||
429 | // Complete hash. | ||
430 | CryptCompleteHash2B(&hashState, &nameHash->b); | ||
431 | } | ||
432 | return; | ||
433 | } |
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[].
Error Returns | Meaning |
TPM_RC_AUTH_FAIL | auth fails and increments DA failure count |
TPM_RC_BAD_AUTH | auth fails but DA does not apply |
434 | static TPM_RC | |||
435 | CheckPWAuthSession( | |||
436 | UINT32 | sessionIndex | // IN: index of session to be processed | |
437 | ) | |||
438 | { | |||
439 | TPM2B_AUTH | authValue; | ||
440 | TPM_HANDLE | associatedHandle = s_associatedHandles[sessionIndex]; |
442 // Strip trailing zeros from the password.
443 MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]); 444
445 // Get the auth value and size.
446 authValue.t.size = EntityGetAuthValue(associatedHandle, &authValue.t.buffer); 447
448 // Success if the digests are identical.
449 if(Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &authValue.b))
450 {
451 return TPM_RC_SUCCESS;
452 }
453 else // if the digests are not identical
454 {
455 // Invoke DA protection if applicable.
456 return IncrementLockout(sessionIndex);
457 }
458 }
This function computes the HMAC for an authorization session in a command.
459 static void
460 ComputeCommandHMAC(
461 UINT32 sessionIndex, // IN: index of session to be processed
462 TPM2B_DIGEST *cpHash, // IN: cpHash
463 TPM2B_DIGEST *hmac // OUT: authorization HMAC
464 )
465 {
TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
TPM2B_KEY key;
BYTE marshalBuffer[sizeof(TPMA_SESSION)];
BYTE *buffer;
UINT32 marshalSize;
HMAC_STATE hmacState;
TPM2B_NONCE *nonceDecrypt;
TPM2B_NONCE *nonceEncrypt;
SESSION *session;
TPM_HT sessionHandleType =
HandleGetType(s_sessionHandles[sessionIndex]); 477
478 nonceDecrypt = NULL;
479 nonceEncrypt = NULL; 480
// Determine if extra nonceTPM values are going to be required.
// If this is the first session (sessionIndex = 0) and it is an authorization
// session that uses an HMAC, then check if additional session nonces are to be
// included.
if( sessionIndex == 0
&& s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
487 {
488 // If there is a decrypt session and if this is not the decrypt session,
489 // then an extra nonce may be needed.
490 if( s_decryptSessionIndex != UNDEFINED_INDEX
491 && s_decryptSessionIndex != sessionIndex)
492 {
493 // Will add the nonce for the decrypt session.
494 SESSION *decryptSession
495 = SessionGet(s_sessionHandles[s_decryptSessionIndex]);
496 nonceDecrypt = &decryptSession->nonceTPM;
497 }
498 // Now repeat for the encrypt session.
499 if( s_encryptSessionIndex != UNDEFINED_INDEX
500 && s_encryptSessionIndex != sessionIndex
501 && s_encryptSessionIndex != s_decryptSessionIndex)
502 {
503 // Have to have the nonce for the encrypt session.
504 SESSION *encryptSession
505 = SessionGet(s_sessionHandles[s_encryptSessionIndex]);
506 nonceEncrypt = &encryptSession->nonceTPM;
507 }
508 }
509
510 // Continue with the HMAC processing.
511 session = SessionGet(s_sessionHandles[sessionIndex]); 512
513 // Generate HMAC key.
514 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer)); 515
// Check if the session has an associated handle and if the associated entity
// is the one to which the session is bound. If not, add the authValue of
// this entity to the HMAC key.
// If the session is bound to the object or the session is a policy session
// with no authValue required, do not include the authValue in the HMAC key.
// Note: For a policy session, its isBound attribute is CLEARED. 522
523 // If the session isn't used for authorization, then there is no auth value
524 // to add
525 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
526 {
// used for auth so see if this is a policy session with authValue needed
// or an hmac session that is not bound
if( sessionHandleType == TPM_HT_POLICY_SESSION
&& session->attributes.isAuthValueNeeded == SET
|| sessionHandleType == TPM_HT_HMAC_SESSION
&& !IsSessionBindEntity(s_associatedHandles[sessionIndex], session)
533 )
534 {
535 // add the authValue to the HMAC key
536 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
537 key.t.size = key.t.size
538 + EntityGetAuthValue(s_associatedHandles[sessionIndex],
539 (AUTH_VALUE *)&(key.t.buffer[key.t.size]));
540 }
541 }
542
543 // if the HMAC key size is 0, a NULL string HMAC is allowed
544 if( key.t.size == 0
545 && s_inputAuthValues[sessionIndex].t.size == 0)
546 {
547 hmac->t.size = 0;
548 return;
549 }
550
551 // Start HMAC
552 hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState); 553
554 // Add cpHash
555 CryptUpdateDigest2B(&hmacState, &cpHash->b); 556
557 // Add nonceCaller
558 CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b); 559
560 // Add nonceTPM
561 CryptUpdateDigest2B(&hmacState, &session->nonceTPM.b); 562
563 // If needed, add nonceTPM for decrypt session
564 if(nonceDecrypt != NULL)
565 CryptUpdateDigest2B(&hmacState, &nonceDecrypt->b);
567 | // If needed, add nonceTPM for encrypt session | |
568 | if(nonceEncrypt != NULL) | |
569 | CryptUpdateDigest2B(&hmacState, &nonceEncrypt->b); | |
570 | ||
571 | // Add sessionAttributes | |
572 | buffer = marshalBuffer; | |
573 | marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), | |
574 | &buffer, NULL); | |
575 | CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer); | |
576 | ||
577 | // Complete the HMAC computation | |
578 | CryptCompleteHMAC2B(&hmacState, &hmac->b); | |
579 | ||
580 | return; | |
581 | } |
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.
Error Returns | Meaning |
TPM_RC_AUTH_FAIL | auth failure caused failureCount increment |
TPM_RC_BAD_AUTH | auth failure did not cause failureCount increment |
582 static TPM_RC
583 CheckSessionHMAC(
584 UINT32 sessionIndex, // IN: index of session to be processed
585 TPM2B_DIGEST *cpHash // IN: cpHash of the command
586 )
587 {
588 TPM2B_DIGEST hmac; // authHMAC for comparing 589
590 // Compute authHMAC
591 ComputeCommandHMAC(sessionIndex, cpHash, &hmac); 592
593 // Compare the input HMAC with the authHMAC computed above.
594 if(!Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &hmac.b))
595 {
596 // If an HMAC session has a failure, invoke the anti-hammering
597 // if it applies to the authorized entity or the session.
598 // Otherwise, just indicate that the authorization is bad.
599 return IncrementLockout(sessionIndex); 600 }
601 return TPM_RC_SUCCESS;
602 }
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.
Error Returns | Meaning |
TPM_RC_PCR_CHANGED | PCR value is not current |
TPM_RC_POLICY_FAIL | policy session fails |
TPM_RC_LOCALITY | command locality is not allowed |
TPM_RC_POLICY_CC | CC doesn't match |
TPM_RC_EXPIRED | policy session has expired |
TPM_RC_PP | PP is required but not asserted |
TPM_RC_NV_UNAVAILABLE | NV is not available for write |
TPM_RC_NV_RATE | NV is rate limiting |
603 static TPM_RC
604 CheckPolicyAuthSession(
605 UINT32 sessionIndex, // IN: index of session to be processed 606 TPM_CC commandCode, // IN: command code
607 TPM2B_DIGEST *cpHash, // IN: cpHash using the algorithm of this 608 // session
609 TPM2B_DIGEST *nameHash // IN: nameHash using the session algorithm 610 )
611 {
612 TPM_RC result = TPM_RC_SUCCESS;
613 SESSION *session;
614 TPM2B_DIGEST authPolicy;
615 TPMI_ALG_HASH policyAlg;
616 UINT8 locality;
617
618 // Initialize pointer to the auth session.
619 session = SessionGet(s_sessionHandles[sessionIndex]); 620
621 // If the command is TPM_RC_PolicySecret(), make sure that 622 // either password or authValue is required
623 if( commandCode == TPM_CC_PolicySecret
624 && session->attributes.isPasswordNeeded == CLEAR 625 && session->attributes.isAuthValueNeeded == CLEAR) 626 return TPM_RC_MODE;
627
628 // See if the PCR counter for the session is still valid.
629 if( !SessionPCRValueIsCurrent(s_sessionHandles[sessionIndex]) ) 630 return TPM_RC_PCR_CHANGED;
631
632 // Get authPolicy.
633 policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], 634 &authPolicy);
635 // Compare authPolicy.
636 if(!Memory2BEqual(&session->u2.policyDigest.b, &authPolicy.b))
637 return TPM_RC_POLICY_FAIL;
638
639 // Policy is OK so check if the other factors are correct 640
641 // Compare policy hash algorithm.
642 if(policyAlg != session->authHashAlg) 643 return TPM_RC_POLICY_FAIL;
644
645 // Compare timeout.
646 if(session->timeOut != 0)
647 {
648 // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE 649 // or TPM_RC_NV_RATE error may be returned here.
650 result = NvIsAvailable();
651 if(result != TPM_RC_SUCCESS) 652 return result;
653
654 if(session->timeOut < go.clock) 655 return TPM_RC_EXPIRED;
656 }
657
658 // If command code is provided it must match 659 if(session->commandCode != 0)
660 {
661 if(session->commandCode != commandCode) 662 return TPM_RC_POLICY_CC;
663 }
664 else
665 {
666 // If command requires a DUP or ADMIN authorization, the session must have 667 // command code set.
668 AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex); 669 if(role == AUTH_ADMIN || role == AUTH_DUP)
670 return TPM_RC_POLICY_FAIL;
671 }
672 // Check command locality.
673 {
674 BYTE sessionLocality[sizeof(TPMA_LOCALITY)]; 675 BYTE *buffer = sessionLocality;
676
677 // Get existing locality setting in canonical form
678 TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL); 679
680 // See if the locality has been set
681 if(sessionLocality[0] != 0)
682 {
683 // If so, get the current locality
684 locality = _plat LocalityGet();
685 if (locality < 5)
686 {
687 if( ((sessionLocality[0] & (1 << locality)) == 0)
688 || sessionLocality[0] > 31)
689 return TPM_RC_LOCALITY;
690 }
691 else if (locality > 31)
692 {
693 if(sessionLocality[0] != locality) 694 return TPM_RC_LOCALITY;
695 }
696 else
697 {
698 // Could throw an assert here but a locality error is just
699 // as good. It just means that, whatever the locality is, it isn't
700 // the locality requested so...
701 return TPM_RC_LOCALITY;
702 }
703 }
704 } // end of locality check 705
706 // Check physical presence.
707 if( session->attributes.isPPRequired == SET 708 && !_plat PhysicalPresenceAsserted())
709 return TPM_RC_PP;
710
711 // Compare cpHash/nameHash if defined, or if the command requires an ADMIN or
712 | // DUP role for this handle. | |
713 | if(session->u1.cpHash.b.size != 0) | |
714 | { | |
715 | if(session->attributes.iscpHashDefined) | |
716 | { | |
717 | // Compare cpHash. | |
718 | if(!Memory2BEqual(&session->u1.cpHash.b, &cpHash->b)) | |
719 | return TPM_RC_POLICY_FAIL; | |
720 | } | |
721 | else | |
722 | { | |
723 | // Compare nameHash. | |
724 | // When cpHash is not defined, nameHash is placed in its space. | |
725 | if(!Memory2BEqual(&session->u1.cpHash.b, &nameHash->b)) | |
726 | return TPM_RC_POLICY_FAIL; | |
727 | } | |
728 | } | |
729 | if(session->attributes.checkNvWritten) | |
730 | { | |
731 | NV_INDEX nvIndex; | |
732 | ||
733 | // If this is not an NV index, the policy makes no sense so fail it. | |
734 | if(HandleGetType(s_associatedHandles[sessionIndex])!= TPM_HT_NV_INDEX) | |
735 | return TPM_RC_POLICY_FAIL; | |
736 | ||
737 | // Get the index data | |
738 | NvGetIndexInfo(s_associatedHandles[sessionIndex], &nvIndex); | |
739 | ||
740 | // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state | |
741 | if( (nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) | |
742 | != (session->attributes.nvWrittenState == SET)) | |
743 | return TPM_RC_POLICY_FAIL; | |
744 | } | |
745 | ||
746 | return TPM_RC_SUCCESS; | |
747 | } |
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.
Error Returns | Meaning |
TPM_RC_SUCCSS | unmarshaled without error |
TPM_RC_SIZE | the number of bytes unmarshaled is not the same as the value for authorizationSize in the command |
748 static TPM_RC
749 RetrieveSessionData (
750 TPM_CC commandCode, // IN: command code
751 UINT32 *sessionCount, // OUT: number of sessions found
752 BYTE *sessionBuffer, // IN: pointer to the session buffer 753 INT32 bufferSize // IN: size of the session buffer 754 )
755 {
756 int sessionIndex;
757 int i;
758 TPM_RC result;
759 SESSION *session;
760 TPM_HT sessionType;
761
762 s_decryptSessionIndex = UNDEFINED_INDEX;
763 s_encryptSessionIndex = UNDEFINED_INDEX; 764 s_auditSessionIndex = UNDEFINED_INDEX; 765
766 for(sessionIndex = 0; bufferSize > 0; sessionIndex++)
767 {
768 // If maximum allowed number of sessions has been parsed, return a size 769 // error with a session number that is larger than the number of allowed 770 // sessions
771 if(sessionIndex == MAX_SESSION_NUM)
772 return TPM_RC_SIZE + TPM_RC_S + g_rcIndex[sessionIndex+1]; 773
774 // make sure that the associated handle for each session starts out 775 // unassigned
776 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; 777
778 // First parameter: Session handle.
779 result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex], 780 &sessionBuffer, &bufferSize, TRUE);
781 if(result != TPM_RC_SUCCESS)
782 return result + TPM_RC_S + g_rcIndex[sessionIndex]; 783
784 // Second parameter: Nonce.
785 result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex], 786 &sessionBuffer, &bufferSize);
787 if(result != TPM_RC_SUCCESS)
788 return result + TPM_RC_S + g_rcIndex[sessionIndex]; 789
790 // Third parameter: sessionAttributes.
791 result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex], 792 &sessionBuffer, &bufferSize);
793 if(result != TPM_RC_SUCCESS)
794 return result + TPM_RC_S + g_rcIndex[sessionIndex]; 795
796 // Fourth parameter: authValue (PW or HMAC).
797 result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex], 798 &sessionBuffer, &bufferSize);
799 if(result != TPM_RC_SUCCESS)
800 return result + TPM_RC_S + g_rcIndex[sessionIndex]; 801
802 if(s_sessionHandles[sessionIndex] == TPM_RS_PW) 803 {
804 // A PWAP session needs additional processing.
805 // Can't have any attributes set other than continueSession bit 806 if( s_attributes[sessionIndex].encrypt
807 || s_attributes[sessionIndex].decrypt
808 || s_attributes[sessionIndex].audit
809 || s_attributes[sessionIndex].auditExclusive
810 || s_attributes[sessionIndex].auditReset
811 )
812 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 813
814 // The nonce size must be zero.
815 if(s_nonceCaller[sessionIndex].t.size != 0)
816 return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex]; 817
818 continue;
819 }
820 // For not password sessions... 821
822 // Find out if the session is loaded.
823 if(!SessionIsLoaded(s_sessionHandles[sessionIndex])) 824 return TPM_RC_REFERENCE_S0 + sessionIndex;
825
826 sessionType = HandleGetType(s_sessionHandles[sessionIndex]); 827 session = SessionGet(s_sessionHandles[sessionIndex]);
828 // Check if the session is an HMAC/policy session.
829 if( ( session->attributes.isPolicy == SET 830 && sessionType == TPM_HT_HMAC_SESSION
831 )
832 || ( session->attributes.isPolicy == CLEAR
833 && sessionType == TPM_HT_POLICY_SESSION
834 )
835 )
836 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex]; 837
838 // Check that this handle has not previously been used. 839 for(i = 0; i < sessionIndex; i++)
840 {
841 if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
842 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex]; 843 }
844
845 // If the session is used for parameter encryption or audit as well, set 846 // the corresponding indices.
847
848 // First process decrypt.
849 if(s_attributes[sessionIndex].decrypt)
850 {
851 // Check if the commandCode allows command parameter encryption. 852 if(DecryptSize(commandCode) == 0)
853 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 854
855 // Encrypt attribute can only appear in one session
856 if(s_decryptSessionIndex != UNDEFINED_INDEX)
857 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 858
859 // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL 860 if(session->symmetric.algorithm == TPM_ALG_NULL)
861 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex]; 862
863 // All checks passed, so set the index for the session used to decrypt 864 // a command parameter.
865 s_decryptSessionIndex = sessionIndex; 866 }
867
868 // Now process encrypt.
869 if(s_attributes[sessionIndex].encrypt)
870 {
871 // Check if the commandCode allows response parameter encryption. 872 if(EncryptSize(commandCode) == 0)
873 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 874
875 // Encrypt attribute can only appear in one session.
876 if(s_encryptSessionIndex != UNDEFINED_INDEX)
877 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 878
879 // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL 880 if(session->symmetric.algorithm == TPM_ALG_NULL)
881 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex]; 882
883 // All checks passed, so set the index for the session used to encrypt 884 // a response parameter.
885 s_encryptSessionIndex = sessionIndex; 886 }
887
888 // At last process audit.
889 if(s_attributes[sessionIndex].audit)
890 {
891 // Audit attribute can only appear in one session.
892 if(s_auditSessionIndex != UNDEFINED_INDEX)
893 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 894
895 | // An audit session can not be policy session. | ||
896 | if( HandleGetType(s_sessionHandles[sessionIndex]) | ||
897 | == TPM_HT_POLICY_SESSION) | ||
898 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; | ||
899 | |||
900 | // If this is a reset of the audit session, or the first use | ||
901 | // of the session as an audit session, it doesn't matter what | ||
902 | // the exclusive state is. The session will become exclusive. | ||
903 | if( s_attributes[sessionIndex].auditReset == CLEAR | ||
904 | && session->attributes.isAudit == SET) | ||
905 | { | ||
906 | // Not first use or reset. If auditExlusive is SET, then this | ||
907 | // session must be the current exclusive session. | ||
908 | if( s_attributes[sessionIndex].auditExclusive == SET | ||
909 | && g_exclusiveAuditSession != s_sessionHandles[sessionIndex]) | ||
910 | return TPM_RC_EXCLUSIVE; | ||
911 | } | ||
912 | |||
913 | s_auditSessionIndex = sessionIndex; | ||
914 | } | ||
915 | |||
916 | // Initialize associated handle as undefined. This will be changed when | ||
917 | // the handles are processed. | ||
918 | s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; | ||
919 | |||
920 | } | ||
921 | |||
922 | // Set the number of sessions found. | ||
923 | *sessionCount = sessionIndex; | ||
924 | return TPM_RC_SUCCESS; | ||
925 | } |
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
Error Returns | Meaning |
TPM_RC_NV_RATE | NV is rate limiting |
TPM_RC_NV_UNAVAILABLE | NV is not available at this time |
TPM_RC_LOCKOUT | TPM is in lockout |
926 static TPM_RC
927 CheckLockedOut(
928 BOOL lockoutAuthCheck // IN: TRUE if checking is for lockoutAuth 929 )
930 {
931 TPM_RC result;
932
933 // If NV is unavailable, and current cycle state recorded in NV is not 934 // SHUTDOWN_NONE, refuse to check any authorization because we would 935 // not be able to handle a DA failure.
936 result = NvIsAvailable();
937 if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE) 938 return result;
939
940 // Check if DA info needs to be updated in NV. 941 if(s_DAPendingOnNV)
942 {
943 // If NV is accessible, ...
944 if(result == TPM_RC_SUCCESS)
945 {
// ... write the pending DA data and proceed.
NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED,
&gp.lockOutAuthEnabled);
NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
g_updateNV = TRUE;
s_DAPendingOnNV = FALSE; 952 }
953 else
954 {
955 // Otherwise no authorization can be checked.
956 return result;
957 }
958 | } | |
959 | ||
960 | // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth | |
961 | // is disabled... | |
962 | if(lockoutAuthCheck) | |
963 | { | |
964 | if(gp.lockOutAuthEnabled == FALSE) | |
965 | return TPM_RC_LOCKOUT; | |
966 | } | |
967 | else | |
968 | { | |
969 | // ... or if the number of failed tries has been maxed out. | |
970 | if(gp.failedTries >= gp.maxTries) | |
971 | return TPM_RC_LOCKOUT; | |
972 | } | |
973 | return TPM_RC_SUCCESS; | |
974 | } |
This function checks that the authorization session properly authorizes the use of the associated handle.
Error Returns | Meaning |
TPM_RC_LOCKOUT | entity is protected by DA and TPM is in lockout, or TPM is locked out on NV update pending on DA parameters |
TPM_RC_PP | Physical Presence is required but not provided |
TPM_RC_AUTH_FAIL | HMAC or PW authorization failed with DA side-effects (can be a policy session) |
TPM_RC_BAD_AUTH | HMAC or PW authorization failed without DA side-effects (can be a policy session) |
TPM_RC_POLICY_FAIL | if policy session fails |
TPM_RC_POLICY_CC | command code of policy was wrong |
TPM_RC_EXPIRED | the policy session has expired |
TPM_RC_PCR | ??? |
TPM_RC_AUTH_UNAVAILABLE | authValue or authPolicy unavailable |
975 | static TPM_RC | ||||
976 | CheckAuthSession( | ||||
977 | TPM_CC | commandCode, | // | IN: | commandCode |
978 | UINT32 | sessionIndex, | // | IN: | index of session to be processed |
979 | TPM2B_DIGEST | *cpHash, | // | IN: | cpHash |
980 | TPM2B_DIGEST | *nameHash | // | IN: | nameHash |
981 | ) | |
982 | { | |
983 | TPM_RC result; | |
984 | SESSION *session = NULL; | |
985 | TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex]; | |
986 | TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex]; | |
987 | TPM_HT sessionHandleType = HandleGetType(sessionHandle); | |
988 | ||
989 | pAssert(sessionHandle != TPM_RH_UNASSIGNED); | |
990 | ||
991 | if(sessionHandle != TPM_RS_PW) | |
992 | session = SessionGet(sessionHandle); | |
993 | ||
994 | pAssert(sessionHandleType != TPM_HT_POLICY_SESSION || session != NULL); | |
995 | ||
996 | // If the authorization session is not a policy session, or if the policy | |
997 | // session requires authorization, then check lockout. | |
998 | if( sessionHandleType != TPM_HT_POLICY_SESSION | |
999 | || session->attributes.isAuthValueNeeded | |
1000 | || session->attributes.isPasswordNeeded) | |
1001 | { | |
1002 | // See if entity is subject to lockout. | |
1003 | if(!IsDAExempted(associatedHandle)) | |
1004 | { | |
1005 | // If NV is unavailable, and current cycle state recorded in NV is not | |
1006 | // SHUTDOWN_NONE, refuse to check any authorization because we would | |
1007 | // not be able to handle a DA failure. | |
1008 | result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT); | |
1009 | if(result != TPM_RC_SUCCESS) | |
1010 | return result; | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | if(associatedHandle == TPM_RH_PLATFORM) | |
1015 | { | |
1016 | // If the physical presence is required for this command, check for PP | |
1017 | // assertion. If it isn't asserted, no point going any further. | |
1018 | if( PhysicalPresenceIsRequired(commandCode) | |
1019 | && !_plat PhysicalPresenceAsserted() | |
1020 | ) | |
1021 | return TPM_RC_PP; | |
1022 | } | |
1023 | // If a policy session is required, make sure that it is being used. | |
1024 | if( IsPolicySessionRequired(commandCode, sessionIndex) | |
1025 | && sessionHandleType != TPM_HT_POLICY_SESSION) | |
1026 | return TPM_RC_AUTH_TYPE; | |
1027 | ||
1028 | // If this is a PW authorization, check it and return. | |
1029 | if(sessionHandle == TPM_RS_PW) | |
1030 | { | |
1031 | if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex)) | |
1032 | return CheckPWAuthSession(sessionIndex); | |
1033 | else | |
1034 | return TPM_RC_AUTH_UNAVAILABLE; | |
1035 | } | |
1036 | // If this is a policy session, ... | |
1037 | if(sessionHandleType == TPM_HT_POLICY_SESSION) | |
1038 | { | |
1039 | // ... see if the entity has a policy, ... | |
1040 | if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex)) | |
1041 | return TPM_RC_AUTH_UNAVAILABLE; | |
1042 | // ... and check the policy session. | |
1043 | result = CheckPolicyAuthSession(sessionIndex, commandCode, | |
1044 | cpHash, nameHash); | |
1045 | if (result != TPM_RC_SUCCESS) | |
1046 | return result; |
1047 | } |
1048 | else |
1049 | { |
1050 | // For non policy, the entity being accessed must allow authorization |
1051 | // with an auth value. This is required even if the auth value is not |
1052 | // going to be used in an HMAC because it is bound. |
1053 | if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex)) |
1054 | return TPM_RC_AUTH_UNAVAILABLE; |
1055 | } |
1056 | // At this point, the session must be either a policy or an HMAC session. |
1057 | session = SessionGet(s_sessionHandles[sessionIndex]); |
1058 | |
1059 | if( sessionHandleType == TPM_HT_POLICY_SESSION |
1060 | && session->attributes.isPasswordNeeded == SET) |
1061 | { |
1062 | // For policy session that requires a password, check it as PWAP session. |
1063 | return CheckPWAuthSession(sessionIndex); |
1064 | } |
1065 | else |
1066 | { |
1067 | // For other policy or HMAC sessions, have its HMAC checked. |
1068 | return CheckSessionHMAC(sessionIndex, cpHash); |
1069 | } |
1070 | } |
1071 | #ifdef TPM_CC_GetCommandAuditDigest |
This function checks if the current command may trigger command audit, and if it is safe to perform the action.
Error Returns | Meaning |
TPM_RC_NV_UNAVAILABLE | NV is not available for write |
TPM_RC_NV_RATE | NV is rate limiting |
1072 static TPM_RC
1073 CheckCommandAudit(
1074 TPM_CC commandCode, // IN: Command code
1075 UINT32 handleNum, // IN: number of element in handle array 1076 TPM_HANDLE handles[], // IN: array of handle
1077 BYTE *parmBufferStart, // IN: start of parameter buffer 1078 UINT32 parmBufferSize // IN: size of parameter buffer 1079 )
1080 {
1081 TPM_RC result = TPM_RC_SUCCESS;
1082
1083 // If audit is implemented, need to check to see if auditing is being done 1084 // for this command.
1085 if(CommandAuditIsRequired(commandCode))
1086 {
1087 // If the audit digest is clear and command audit is required, NV must be 1088 // available so that TPM2_GetCommandAuditDigest() is able to increment
1089 // audit counter. If NV is not available, the function bails out to prevent 1090 // the TPM from attempting an operation that would fail anyway.
1091 if( gr.commandAuditDigest.t.size == 0
1092 || commandCode == TPM_CC_GetCommandAuditDigest) 1093 {
1094 result = NvIsAvailable();
1095 if(result != TPM_RC_SUCCESS) 1096 return result;
1097 }
1098 ComputeCpHash(gp.auditHashAlg, commandCode, handleNum,
1099 | handles, parmBufferSize, parmBufferStart, | |
1100 | &s_cpHashForCommandAudit, NULL); | |
1101 | } | |
1102 |
1103 return TPM_RC_SUCCESS;
1104 }
1105 #endif
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.
Error Returns | Meaning |
various | parsing failure or authorization failure |
1106 | TPM_RC | |
1107 | ParseSessionBuffer( | |
1108 | TPM_CC commandCode, // IN: Command code | |
1109 | UINT32 handleNum, // IN: number of element in handle | array |
1110 | TPM_HANDLE handles[], // IN: array of handle | |
1111 | BYTE *sessionBufferStart, // IN: start of session buffer | |
1112 | UINT32 sessionBufferSize, // IN: size of session buffer | |
1113 | BYTE *parmBufferStart, // IN: start of parameter buffer | |
1114 | UINT32 parmBufferSize // IN: size of parameter buffer | |
1115 | ) | |
1116 | { | |
1117 | TPM_RC result; | |
1118 | UINT32 i; | |
1119 | INT32 size = 0; | |
1120 | TPM2B_AUTH extraKey; | |
1121 | UINT32 sessionIndex; | |
1122 | SESSION *session; | |
1123 | TPM2B_DIGEST cpHash; | |
1124 | TPM2B_DIGEST nameHash; | |
1125 | TPM_ALG_ID cpHashAlg = TPM_ALG_NULL; // algID for the last computed | |
1126 | // cpHash | |
1127 | ||
1128 | // Check if a command allows any session in its session area. | |
1129 | if(!IsSessionAllowed(commandCode)) | |
1130 | return TPM_RC_AUTH_CONTEXT; | |
1131 | ||
1132 | // Default-initialization. | |
1133 | s_sessionNum = 0; | |
1134 | cpHash.t.size = 0; | |
1135 | ||
1136 | result = RetrieveSessionData(commandCode, &s_sessionNum, | |
1137 | sessionBufferStart, sessionBufferSize); | |
1138 | if(result != TPM_RC_SUCCESS) | |
1139 | return result; | |
1140 | ||
1141 | // There is no command in the TPM spec that has more handles than | |
1142 | // MAX_SESSION_NUM. | |
1143 | pAssert(handleNum <= MAX_SESSION_NUM); | |
1144 | ||
1145 | // Associate the session with an authorization handle. | |
1146 | for(i = 0; i < handleNum; i++) | |
1147 | { | |
1148 | if(CommandAuthRole(commandCode, i) != AUTH_NONE) | |
1149 | { | |
1150 | // If the received session number is less than the number of handle | |
1151 | // that requires authorization, an error should be returned. |
1152 // Note: for all the TPM 2.0 commands, handles requiring
1153 // authorization come first in a command input.
1154 if(i > (s_sessionNum - 1))
1155 return TPM_RC_AUTH_MISSING;
1156
1157 // Record the handle associated with the authorization session 1158 s_associatedHandles[i] = handles[i];
1159 }
1160 }
1161
1162 // Consistency checks are done first to avoid auth failure when the command 1163 // will not be executed anyway.
1164 for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++) 1165 {
1166 // PW session must be an authorization session 1167 if(s_sessionHandles[sessionIndex] == TPM_RS_PW ) 1168 {
1169 if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED) 1170 return TPM_RC_HANDLE + g_rcIndex[sessionIndex];
1171 }
1172 else
1173 {
1174 session = SessionGet(s_sessionHandles[sessionIndex]); 1175
1176 // A trial session can not appear in session area, because it cannot 1177 // be used for authorization, audit or encrypt/decrypt.
1178 if(session->attributes.isTrialPolicy == SET)
1179 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 1180
1181 // See if the session is bound to a DA protected entity
1182 // NOTE: Since a policy session is never bound, a policy is still 1183 // usable even if the object is DA protected and the TPM is in 1184 // lockout.
1185 if(session->attributes.isDaBound == SET)
1186 {
1187 result = CheckLockedOut(session->attributes.isLockoutBound == SET);
1188 if(result != TPM_RC_SUCCESS) 1189 return result;
1190 }
1191 // If the current cpHash is the right one, don't re-compute. 1192 if(cpHashAlg != session->authHashAlg) // different so compute 1193 {
1194 cpHashAlg = session->authHashAlg; // save this new algID
1195 ComputeCpHash(session->authHashAlg, commandCode, handleNum, 1196 handles, parmBufferSize, parmBufferStart,
1197 &cpHash, &nameHash);
1198 }
1199 // If this session is for auditing, save the cpHash.
1200 if(s_attributes[sessionIndex].audit) 1201 s_cpHashForAudit = cpHash;
1202 }
1203
1204 // if the session has an associated handle, check the auth 1205 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) 1206 {
1207 result = CheckAuthSession(commandCode, sessionIndex, 1208 &cpHash, &nameHash);
1209 if(result != TPM_RC_SUCCESS)
1210 return RcSafeAddToResult(result,
1211 TPM_RC_S + g_rcIndex[sessionIndex]);
1212 }
1213 else
1214 {
1215 // a session that is not for authorization must either be encrypt, 1216 // decrypt, or audit
1217 if( s_attributes[sessionIndex].audit == CLEAR
1218 && s_attributes[sessionIndex].encrypt == CLEAR
1219 && s_attributes[sessionIndex].decrypt == CLEAR)
1220 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; 1221
1222 // check HMAC for encrypt/decrypt/audit only sessions
1223 result = CheckSessionHMAC(sessionIndex, &cpHash);
1224 if(result != TPM_RC_SUCCESS)
1225 return RcSafeAddToResult(result,
1226 TPM_RC_S + g_rcIndex[sessionIndex]);
1227 }
1228 }
1229
1230 #ifdef TPM_CC_GetCommandAuditDigest
1231 // Check if the command should be audited.
1232 result = CheckCommandAudit(commandCode, handleNum, handles, 1233 parmBufferStart, parmBufferSize); 1234 if(result != TPM_RC_SUCCESS)
1235 return result; // No session number to reference 1236 #endif
1237
1238 // Decrypt the first parameter if applicable. This should be the last operation 1239 // in session processing.
1240 // If the encrypt session is associated with a handle and the handle's
1241 // authValue is available, then authValue is concatenated with sessionAuth to 1242 // generate encryption key, no matter if the handle is the session bound entity 1243 // or not.
1244 if(s_decryptSessionIndex != UNDEFINED_INDEX) 1245 {
1246 // Get size of the leading size field in decrypt parameter
1247 if( s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED 1248 && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex],
1249 commandCode,
1250 s_decryptSessionIndex)
1251 )
1252 {
1253 extraKey.b.size=
1254 EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex],
1255 &extraKey.t.buffer);
1256 }
1257 else
1258 {
1259 extraKey.b.size = 0;
1260 }
1261 size = DecryptSize(commandCode);
1262 result = CryptParameterDecryption(
1263 s_sessionHandles[s_decryptSessionIndex],
1264 &s_nonceCaller[s_decryptSessionIndex].b,
1265 parmBufferSize, (UINT16)size,
1266 &extraKey,
1267 parmBufferStart);
1268 if(result != TPM_RC_SUCCESS)
1269 return RcSafeAddToResult(result,
1270 | ||
1271 | } | |
1272 | ||
1273 | return TPM_RC_SUCCESS; | |
1274 | } |
TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
Function to process a command with no session associated. The function makes sure all the handles in the command require no authorization.
Error Returns | Meaning |
TPM_RC_AUTH_MISSING | failure - one or more handles require auth |
1275 TPM_RC
1276 CheckAuthNoSession(
1277 TPM_CC commandCode, // IN: Command Code
1278 UINT32 handleNum, // IN: number of handles in command 1279 TPM_HANDLE handles[], // IN: array of handle
1280 BYTE *parmBufferStart, // IN: start of parameter buffer 1281 UINT32 parmBufferSize // IN: size of parameter buffer 1282 )
1283 {
1284 UINT32 i;
1285 TPM_RC result = TPM_RC_SUCCESS;
1286
1287 // Check if the commandCode requires authorization 1288 for(i = 0; i < handleNum; i++)
1289 {
1290 if(CommandAuthRole(commandCode, i) != AUTH_NONE) 1291 return TPM_RC_AUTH_MISSING;
1292 }
1293
1294 #ifdef TPM_CC_GetCommandAuditDigest
1295 // Check if the command should be audited.
1296 result = CheckCommandAudit(commandCode, handleNum, handles, 1297 parmBufferStart, parmBufferSize); 1298 if(result != TPM_RC_SUCCESS) return result;
1299 #endif
1300
1301 // Initialize number of sessions to be 0 1302 s_sessionNum = 0;
1303
1304 return TPM_RC_SUCCESS;
1305 }
The following functions build the session area in a response, and handle the audit sessions (if present).
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.
1306 static void
1307 ComputeRpHash(
1308 TPM_ALG_ID hashAlg, // IN: hash algorithm to compute rpHash 1309 TPM_CC commandCode, // IN: commandCode
1310 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1311 BYTE *resParmBuffer, // IN: response parameter buffer
1312 TPM2B_DIGEST *rpHash // OUT: rpHash
1313 )
1314 {
1315 // The command result in rpHash is always TPM_RC_SUCCESS. 1316 TPM_RC responseCode = TPM_RC_SUCCESS;
1317 HASH_STATE hashState;
1318
1319 // rpHash := hash(responseCode || commandCode || parameters)
1320
1321 // Initiate hash creation.
1322 rpHash->t.size = CryptStartHash(hashAlg, &hashState); 1323
1324 // Add hash constituents.
1325 CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode); 1326 CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode); 1327 CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer); 1328
1329 // Complete hash computation.
1330 CryptCompleteHash2B(&hashState, &rpHash->b);
1331
1332 return;
1333 }
This function initializes the audit data in an audit session.
1334 static void
1335 InitAuditSession(
1336 SESSION *session // session to be initialized 1337 )
1338 {
1339 // Mark session as an audit session. 1340 session->attributes.isAudit = SET; 1341
1342 // Audit session can not be bound. 1343 session->attributes.isBound = CLEAR; 1344
1345 // Size of the audit log is the size of session hash algorithm digest.
1346 session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg); 1347
1348 // Set the original digest value to be 0. 1349 MemorySet(&session->u2.auditDigest.t.buffer,
1350 0,
1351 session->u2.auditDigest.t.size);
1352
1353 return;
1354 }
This function updates the audit digest in an audit session.
1355 static void
1356 Audit(
1357 SESSION *auditSession, // IN: loaded audit session 1358 TPM_CC commandCode, // IN: commandCode
1359 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1360 BYTE *resParmBuffer // IN: response parameter buffer
1361 )
1362 {
1363 TPM2B_DIGEST rpHash; // rpHash for response 1364 HASH_STATE hashState;
1365
1366 // Compute rpHash
1367 ComputeRpHash(auditSession->authHashAlg,
1368 commandCode,
1369 resParmBufferSize,
1370 resParmBuffer,
1371 &rpHash);
1372
1373 // auditDigestnew := hash (auditDigestold || cpHash || rpHash) 1374
1375 // Start hash computation.
1376 CryptStartHash(auditSession->authHashAlg, &hashState);
1377
1378 // Add old digest.
1379 CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b);
1380
1381 // Add cpHash and rpHash.
1382 CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b);
1383 CryptUpdateDigest2B(&hashState, &rpHash.b);
1384
1385 // Finalize the hash.
1386 CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b);
1387
1388 return;
1389 }
1390 #ifdef TPM_CC_GetCommandAuditDigest
This function updates the command audit digest.
1391 static void
1392 CommandAudit(
1393 TPM_CC commandCode, // IN: commandCode
1394 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1395 BYTE *resParmBuffer // IN: response parameter buffer
1396 )
1397 {
1398 if(CommandAuditIsRequired(commandCode))
1399 {
1400 TPM2B_DIGEST rpHash; // rpHash for response 1401 HASH_STATE hashState;
1402
1403 // Compute rpHash.
1404 ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize, 1405 resParmBuffer, &rpHash);
1406
1407 // If the digest.size is one, it indicates the special case of changing 1408 // the audit hash algorithm. For this case, no audit is done on exit.
1409 // NOTE: When the hash algorithm is changed, g_updateNV is set in order to 1410 // force an update to the NV on exit so that the change in digest will 1411 // be recorded. So, it is safe to exit here without setting any flags
1412 // because the digest change will be written to NV when this code exits. 1413 if(gr.commandAuditDigest.t.size == 1)
1414 {
1415 gr.commandAuditDigest.t.size = 0;
1416 return;
1417 }
1418
1419 // If the digest size is zero, need to start a new digest and increment 1420 // the audit counter.
1421 if(gr.commandAuditDigest.t.size == 0)
1422 {
1423 gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg); 1424 MemorySet(gr.commandAuditDigest.t.buffer,
1425 0,
1426 gr.commandAuditDigest.t.size);
1427
1428 // Bump the counter and save its value to NV.
1429 gp.auditCounter++;
1430 NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
1431 g_updateNV = TRUE;
1432 }
1433
1434 // auditDigestnew := hash (auditDigestold || cpHash || rpHash) 1435
1436 // Start hash computation.
1437 CryptStartHash(gp.auditHashAlg, &hashState);
1438
1439 // Add old digest.
1440 CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b);
1441
1442 // Add cpHash
1443 CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b);
1444
1445 // Add rpHash
1446 CryptUpdateDigest2B(&hashState, &rpHash.b);
1447
1448 // Finalize the hash.
1449 CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b);
1450 }
1451 return;
1452 }
1453 #endif
Function to update the internal audit related states of a session. It
initializes the session as audit session and sets it to be exclusive if this is the first time it is used for audit or audit reset was requested;
reports exclusive audit session;
extends audit log; and
clears exclusive audit session if no audit session found in the command.
1454 static void
1455 UpdateAuditSessionStatus(
1456 TPM_CC commandCode, // IN: commandCode
1457 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1458 BYTE *resParmBuffer // IN: response parameter buffer
1459 )
1460 {
1461 UINT32 i;
1462 TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
1463
1464 // Iterate through sessions
1465 for (i = 0; i < s_sessionNum; i++) 1466 {
1467 SESSION *session;
1468
1469 // PW session do not have a loaded session and can not be an audit 1470 // session either. Skip it.
1471 if(s_sessionHandles[i] == TPM_RS_PW) continue; 1472
1473 session = SessionGet(s_sessionHandles[i]); 1474
1475 // If a session is used for audit
1476 if(s_attributes[i].audit == SET)
1477 {
1478 // An audit session has been found
1479 auditSession = s_sessionHandles[i]; 1480
1481 // If the session has not been an audit session yet, or
1482 // the auditSetting bits indicate a reset, initialize it and set
1483 // it to be the exclusive session
1484 if( session->attributes.isAudit == CLEAR 1485 || s_attributes[i].auditReset == SET
1486 )
1487 {
1488 InitAuditSession(session);
1489 g_exclusiveAuditSession = auditSession; 1490 }
1491 else
1492 {
1493 // Check if the audit session is the current exclusive audit
1494 // session and, if not, clear previous exclusive audit session.
1495 if(g_exclusiveAuditSession != auditSession)
1496 g_exclusiveAuditSession = TPM_RH_UNASSIGNED; 1497 }
1498
1499 // Report audit session exclusivity.
1500 if(g_exclusiveAuditSession == auditSession)
1501 {
1502 s_attributes[i].auditExclusive = SET; 1503 }
1504 else
1505 {
1506 s_attributes[i].auditExclusive = CLEAR; 1507 }
1508
1509 // Extend audit log.
1510 Audit(session, commandCode, resParmBufferSize, resParmBuffer); 1511 }
1512 }
1513
1514 // If no audit session is found in the command, and the command allows 1515 // a session then, clear the current exclusive
1516 // audit session.
1517 if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode)) 1518 {
1519 g_exclusiveAuditSession = TPM_RH_UNASSIGNED; 1520 }
1521
1522 return;
1523 }
Function to compute HMAC for authorization session in a response.
1524 static void
1525 ComputeResponseHMAC(
1526 UINT32 sessionIndex, // IN: session index to be processed 1527 SESSION *session, // IN: loaded session
1528 TPM_CC commandCode, // IN: commandCode 1529 TPM2B_NONCE *nonceTPM, // IN: nonceTPM
1530 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1531 BYTE *resParmBuffer, // IN: response parameter buffer
1532 TPM2B_DIGEST *hmac // OUT: authHMAC
1533 )
1534 {
1535 TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1536 TPM2B_KEY key; // HMAC key
1537 BYTE marshalBuffer[sizeof(TPMA_SESSION)];
1538 BYTE *buffer;
1539 UINT32 marshalSize;
1540 HMAC_STATE hmacState;
1541 TPM2B_DIGEST rp_hash;
1542
1543 // Compute rpHash.
1544 ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize, 1545 resParmBuffer, &rp_hash);
1546
1547 // Generate HMAC key
1548 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer)); 1549
1550 // Check if the session has an associated handle and the associated entity is 1551 // the one that the session is bound to.
1552 // If not bound, add the authValue of this entity to the HMAC key. 1553 if( s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED
1554 && !( HandleGetType(s_sessionHandles[sessionIndex]) 1555 == TPM_HT_POLICY_SESSION
1556 && session->attributes.isAuthValueNeeded == CLEAR) 1557 && !session->attributes.requestWasBound)
1558 {
1559 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer)); 1560 key.t.size = key.t.size +
1561 EntityGetAuthValue(s_associatedHandles[sessionIndex],
1562 (AUTH_VALUE *)&key.t.buffer[key.t.size]);
1563 | } | |
1564 | ||
1565 | // if the HMAC key size for a policy session is 0, the response HMAC is | |
1566 | // computed according to the input HMAC | |
1567 | if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION | |
1568 | && key.t.size == 0 | |
1569 | && s_inputAuthValues[sessionIndex].t.size == 0) | |
1570 | { | |
1571 | hmac->t.size = 0; | |
1572 | return; | |
1573 | } | |
1574 | ||
1575 | // Start HMAC computation. | |
1576 | hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState); | |
1577 | ||
1578 | // Add hash components. | |
1579 | CryptUpdateDigest2B(&hmacState, &rp_hash.b); | |
1580 | CryptUpdateDigest2B(&hmacState, &nonceTPM->b); | |
1581 | CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b); | |
1582 | ||
1583 | // Add session attributes. | |
1584 | buffer = marshalBuffer; | |
1585 | marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL); | |
1586 | CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer); | |
1587 | ||
1588 | // Finalize HMAC. | |
1589 | CryptCompleteHMAC2B(&hmacState, &hmac->b); | |
1590 | ||
1591 | return; | |
1592 | } |
Function to compute response for an authorization session.
1593 static void
1594 BuildSingleResponseAuth(
1595 UINT32 sessionIndex, // IN: session index to be processed 1596 TPM_CC commandCode, // IN: commandCode
1597 UINT32 resParmBufferSize, // IN: size of response parameter buffer 1598 BYTE *resParmBuffer, // IN: response parameter buffer
1599 TPM2B_AUTH *auth // OUT: authHMAC
1600 )
1601 {
1602 // For password authorization, field is empty. 1603 if(s_sessionHandles[sessionIndex] == TPM_RS_PW) 1604 {
1605 auth->t.size = 0;
1606 }
1607 else
1608 {
1609 // Fill in policy/HMAC based session response.
1610 SESSION *session = SessionGet(s_sessionHandles[sessionIndex]); 1611
1612 // If the session is a policy session with isPasswordNeeded SET, the auth 1613 // field is empty.
1614 if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION 1615 && session->attributes.isPasswordNeeded == SET)
1616 auth->t.size = 0;
1617 else
1618 // Compute response HMAC.
1619 ComputeResponseHMAC(sessionIndex,
1620 session,
1621 commandCode,
1622 &session->nonceTPM,
1623 resParmBufferSize,
1624 resParmBuffer,
1625 auth);
1626 }
1627
1628 return;
1629 }
Updates TPM nonce in both internal session or response if applicable.
1630 static void
1631 UpdateTPMNonce(
1632 UINT16 noncesSize, // IN: number of elements in 'nonces' array 1633 TPM2B_NONCE nonces[] // OUT: nonceTPM
1634 )
1635 {
1636 UINT32 i;
1637 pAssert(noncesSize >= s_sessionNum); 1638 for(i = 0; i < s_sessionNum; i++) 1639 {
1640 SESSION *session;
1641 // For PW session, nonce is 0.
1642 if(s_sessionHandles[i] == TPM_RS_PW)
1643 {
1644 nonces[i].t.size = 0;
1645 continue;
1646 }
1647 session = SessionGet(s_sessionHandles[i]);
1648 // Update nonceTPM in both internal session and response.
1649 CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer); 1650 nonces[i] = session->nonceTPM;
1651 }
1652 return;
1653 }
Updates internal sessions:
Restarts session time, and
Clears a policy session since nonce is rolling.
1654 static void
1655 UpdateInternalSession(
1656 void
1657 )
1658 {
1659 UINT32 i;
1660 for(i = 0; i < s_sessionNum; i++) 1661 {
1662 // For PW session, no update.
1663 if(s_sessionHandles[i] == TPM_RS_PW) continue; 1664
1665 if(s_attributes[i].continueSession == CLEAR) 1666 {
1667 // Close internal session.
1668 SessionFlush(s_sessionHandles[i]);
1669 }
1670 else
1671 {
1672 // If nonce is rolling in a policy session, the policy related data 1673 // will be re-initialized.
1674 if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION) 1675 {
1676 SESSION *session = SessionGet(s_sessionHandles[i]); 1677
1678 // When the nonce rolls it starts a new timing interval for the
1679 // policy session.
1680 SessionResetPolicyData(session);
1681 session->startTime = go.clock; 1682 }
1683 }
1684 }
1685 return;
1686 }
Function to build Session buffer in a response.
1687 void
1688 BuildResponseSession(
1689 TPM_ST tag, // IN: tag
1690 TPM_CC commandCode, // IN: commandCode
1691 UINT32 resHandleSize, // IN: size of response handle buffer 1692 UINT32 resParmSize, // IN: size of response parameter buffer 1693 UINT32 *resSessionSize // OUT: response session area
1694 )
1695 {
1696 BYTE *resParmBuffer;
1697 TPM2B_NONCE responseNonces[MAX_SESSION_NUM];
1698
1699 // Compute response parameter buffer start.
1700 resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) + 1701 sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize;
1702
1703 // For TPM_ST_SESSIONS, there is parameterSize field. 1704 if(tag == TPM_ST_SESSIONS)
1705 resParmBuffer += sizeof(UINT32); 1706
1707 // Session nonce should be updated before parameter encryption 1708 if(tag == TPM_ST_SESSIONS)
1709 | { | |
1710 | UpdateTPMNonce(MAX_SESSION_NUM, responseNonces); | |
1711 | ||
1712 | // Encrypt first parameter if applicable. Parameter encryption should | |
1713 | // happen after nonce update and before any rpHash is computed. | |
1714 | // If the encrypt session is associated with a handle, the authValue of | |
1715 | // this handle will be concatenated with sessionAuth to generate | |
1716 | // encryption key, no matter if the handle is the session bound entity | |
1717 | // or not. The authValue is added to sessionAuth only when the authValue | |
1718 | // is available. | |
1719 | if(s_encryptSessionIndex != UNDEFINED_INDEX) | |
1720 | { | |
1721 | UINT32 size; | |
1722 | TPM2B_AUTH extraKey; | |
1723 | ||
1724 | // Get size of the leading size field | |
1725 | if( s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED | |
1726 | && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex], | |
1727 | commandCode, s_encryptSessionIndex) | |
1728 | ) | |
1729 | { | |
1730 | extraKey.b.size = | |
1731 | EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex], | |
1732 | &extraKey.t.buffer); | |
1733 | } | |
1734 | else | |
1735 | { | |
1736 | extraKey.b.size = 0; | |
1737 | } | |
1738 | size = EncryptSize(commandCode); | |
1739 | CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex], | |
1740 | &s_nonceCaller[s_encryptSessionIndex].b, | |
1741 | (UINT16)size, | |
1742 | &extraKey, | |
1743 | resParmBuffer); | |
1744 | ||
1745 | } | |
1746 | ||
1747 | } | |
1748 | // | Audit session should be updated first regardless of the tag. |
1749 | // | A command with no session may trigger a change of the exclusivity state. |
1750 UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer); 1751
1752 // Audit command.
1753 CommandAudit(commandCode, resParmSize, resParmBuffer); 1754
1755 // Process command with sessions. 1756 if(tag == TPM_ST_SESSIONS)
1757 {
1758 UINT32 i;
1759 BYTE *buffer;
1760 TPM2B_DIGEST responseAuths[MAX_SESSION_NUM];
1761
1762 pAssert(s_sessionNum > 0);
1763
1764 // Iterate over each session in the command session area, and create 1765 // corresponding sessions for response.
1766 for(i = 0; i < s_sessionNum; i++)
1767 {
1768 BuildSingleResponseAuth(
1769 i,
1770 commandCode,
1771 resParmSize,
1772 resParmBuffer,
1773 &responseAuths[i]);
1774 // Make sure that continueSession is SET on any Password session.
1775 // This makes it marginally easier for the management software 1776 // to keep track of the closed sessions.
1777 if( s_attributes[i].continueSession == CLEAR 1778 && s_sessionHandles[i] == TPM_RS_PW)
1779 {
1780 s_attributes[i].continueSession = SET; 1781 }
1782 }
1783
1784 // Assemble Response Sessions.
1785 *resSessionSize = 0;
1786 buffer = resParmBuffer + resParmSize;
1787 for(i = 0; i < s_sessionNum; i++)
1788 {
1789 *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i], 1790 &buffer, NULL);
1791 *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i], 1792 &buffer, NULL);
1793 *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i], 1794 &buffer, NULL);
1795 | } | |
1796 | ||
1797 | // Update internal sessions after completing response buffer computation. | |
1798 | UpdateInternalSession(); | |
1799 | } | |
1800 | else | |
1801 | { | |
1802 | // Process command with no session. | |
1803 | *resSessionSize = 0; | |
1804 | } | |
1805 | ||
1806 | return; | |
1807 | } |
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.
Attestation Command Support (Attest_spt.c)
#include "InternalRoutines.h"
#include "Attest_spt_fp.h"
Fill in common fields of TPMS_ATTEST structure.
Error Returns | Meaning |
TPM_RC_KEY | key referenced by signHandle is not a signing key |
TPM_RC_SCHEME | both scheme and key's default scheme are empty; or scheme is empty while key's default scheme requires explicit input scheme (split signing); or non-empty default key scheme differs from scheme |
TPM_RC
FillInAttestInfo(
TPMI_DH_OBJECT signHandle, // IN: handle of signing object
TPMT_SIG_SCHEME *scheme, // IN/OUT: scheme to be used for signing
TPM2B_DATA *data, // IN: qualifying data
TPMS_ATTEST *attest // OUT: attest structure 9 )
10 {
TPM_RC result;
TPMI_RH_HIERARCHY signHierarhcy; 13
result = CryptSelectSignScheme(signHandle, scheme);
if(result != TPM_RC_SUCCESS)
return result; 17
// Magic number
attest->magic = TPM_GENERATED_VALUE; 20
21 if(signHandle == TPM_RH_NULL) 22 {
BYTE *buffer;
// For null sign handle, the QN is TPM_RH_NULL
buffer = attest->qualifiedSigner.t.name;
attest->qualifiedSigner.t.size =
TPM_HANDLE_Marshal(&signHandle, &buffer, NULL); 28 }
29 else
30 {
// Certifying object qualified name
// if the scheme is anonymous, this is an empty buffer
if(CryptIsSchemeAnonymous(scheme->scheme))
34 | attest->qualifiedSigner.t.size = 0; | |
35 | else | |
36 | ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner); | |
37 | } | |
38 | ||
39 | // current clock in plain text | |
40 | TimeFillInfo(&attest->clockInfo); | |
41 | ||
42 | // Firmware version in plain text | |
43 | attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8)); | |
44 | attest->firmwareVersion += gp.firmwareV2; | |
45 | ||
46 | // Get the hierarchy of sign object. For NULL sign handle, the hierarchy | |
47 | // will be TPM_RH_NULL | |
48 | signHierarhcy = EntityGetHierarchy(signHandle); | |
49 | if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT) | |
50 | { | |
51 | // For sign object is not in platform or endorsement hierarchy, | |
52 | // obfuscate the clock and firmwereVersion information | |
53 | UINT64 obfuscation[2]; | |
54 | TPMI_ALG_HASH hashAlg; | |
55 | ||
56 | // Get hash algorithm | |
57 | if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER) | |
58 | { | |
59 | hashAlg = CONTEXT_INTEGRITY_HASH_ALG; | |
60 | } | |
61 | else | |
62 | { | |
63 | OBJECT *signObject = NULL; | |
64 | signObject = ObjectGet(signHandle); | |
65 | hashAlg = signObject->publicArea.nameAlg; | |
66 | } | |
67 | KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE", | |
68 | &attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL); | |
69 | ||
70 | // Obfuscate data | |
71 | attest->firmwareVersion += obfuscation[0]; | |
72 | attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32); | |
73 | attest->clockInfo.restartCount += (UINT32)obfuscation[1]; | |
74 | } | |
75 | ||
76 | // External data | |
77 | if(CryptIsSchemeAnonymous(scheme->scheme)) | |
78 | attest->extraData.t.size = 0; | |
79 | else | |
80 | { | |
81 | // If we move the data to the attestation structure, then we will not use | |
82 | // it in the signing operation except as part of the signed data | |
83 | attest->extraData = *data; | |
84 | data->t.size = 0; | |
85 | } | |
86 | ||
87 | return TPM_RC_SUCCESS; | |
88 | } |
Sign a TPMS_ATTEST structure. If signHandle is TPM_RH_NULL, a null signature is returned.
Error Returns | Meaning |
TPM_RC_ATTRIBUTES | signHandle references not a signing key |
TPM_RC_SCHEME | scheme is not compatible with signHandle type |
TPM_RC_VALUE | digest generated for the given scheme is greater than the modulus of signHandle (for an RSA key); invalid commit status or failed to generate r value (for an ECC key) |
TPM_RC
SignAttestInfo(
TPMI_DH_OBJECT signHandle, // IN: handle of sign object
TPMT_SIG_SCHEME *scheme, // IN: sign scheme
TPMS_ATTEST *certifyInfo, // IN: the data to be signed
TPM2B_DATA *qualifyingData, // IN: extra data for the signing proce
TPM2B_ATTEST *attest, // OUT: marshaled attest blob to be
// signed
TPMT_SIGNATURE *signature // OUT: signature 98 )
99 {
TPM_RC result;
TPMI_ALG_HASH hashAlg;
BYTE *buffer;
HASH_STATE hashState;
TPM2B_DIGEST digest; 105
// Marshal TPMS_ATTEST structure for hash
buffer = attest->t.attestationData;
attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, NULL); 109
110 if(signHandle == TPM_RH_NULL)
111 {
112 signature->sigAlg = TPM_ALG_NULL;
113 }
114 else
115 {
// Attestation command may cause the orderlyState to be cleared due to
// the reporting of clock info. If this is the case, check if NV is
// available first
if(gp.orderlyState != SHUTDOWN_NONE)
120 {
// The command needs NV update. Check if NV is available.
// A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
// this point
result = NvIsAvailable();
if(result != TPM_RC_SUCCESS)
return result;
127 }
128
// Compute hash
hashAlg = scheme->details.any.hashAlg;
digest.t.size = CryptStartHash(hashAlg, &hashState);
CryptUpdateDigest(&hashState, attest->t.size, attest->t.attestationData);
CryptCompleteHash2B(&hashState, &digest.b); 134
// If there is qualifying data, need to rehash the the data
// hash(qualifyingData || hash(attestationData))
if(qualifyingData->t.size != 0)
138 {
CryptStartHash(hashAlg, &hashState);
CryptUpdateDigest(&hashState,
qualifyingData->t.size,
qualifyingData->t.buffer);
CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer);
CryptCompleteHash2B(&hashState, &digest.b);
145 | } | |
146 | ||
147 | // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or | |
148 | // TPM_RC_ATTRIBUTES error may be returned at this point | |
149 | return CryptSign(signHandle, | |
150 | scheme, | |
151 | &digest, | |
152 | signature); | |
153 | } | |
154 |
155 return TPM_RC_SUCCESS;
156 }
Context Management Command Support (Context_spt.c)
#include "InternalRoutines.h"
#include "Context_spt_fp.h"
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
void
ComputeContextProtectionKey(
TPMS_CONTEXT *contextBlob, // IN: context blob
TPM2B_SYM_KEY *symKey, // OUT: the symmetric key
TPM2B_IV *iv // OUT: the IV. 8 )
9 {
UINT16 symKeyBits; // number of bits in the parent's
// symmetric key
TPM2B_AUTH *proof = NULL; // the proof value to use. Is null for
// everything but a primary object in
// the Endorsement Hierarchy
15
16 BYTE kdfResult[sizeof(TPMU_HA) * 2];// Value produced by the KDF 17
18 TPM2B_DATA sequence2B, handle2B; 19
// Get proof value
proof = HierarchyGetProof(contextBlob->hierarchy); 22
// Get sequence value in 2B format
sequence2B.t.size = sizeof(contextBlob->sequence);
MemoryCopy(sequence2B.t.buffer, &contextBlob->sequence,
sizeof(contextBlob->sequence),
sizeof(sequence2B.t.buffer)); 28
// Get handle value in 2B format
handle2B.t.size = sizeof(contextBlob->savedHandle);
MemoryCopy(handle2B.t.buffer, &contextBlob->savedHandle,
sizeof(contextBlob->savedHandle),
sizeof(handle2B.t.buffer)); 34
// Get the symmetric encryption key size
symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
symKeyBits = CONTEXT_ENCRYPT_KEY_BITS;
// Get the size of the IV for the algorithm
iv->t.size = CryptGetSymmetricBlockSize(CONTEXT_ENCRYPT_ALG, symKeyBits); 40
// KDFa to generate symmetric key and IV value
KDFa(CONTEXT_INTEGRITY_HASH_ALG, &proof->b, "CONTEXT", &sequence2B.b,
&handle2B.b, (symKey->t.size + iv->t.size) * 8, kdfResult, NULL); 44
// Copy part of the returned value as the key
MemoryCopy(symKey->t.buffer, kdfResult, symKey->t.size,
sizeof(symKey->t.buffer)); 48
// Copy the rest as the IV
MemoryCopy(iv->t.buffer, &kdfResult[symKey->t.size], iv->t.size,
sizeof(iv->t.buffer)); 52
53 return; 54 }
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
void
ComputeContextIntegrity(
TPMS_CONTEXT *contextBlob, // IN: context blob
TPM2B_DIGEST *integrity // OUT: integrity 59 )
60 {
HMAC_STATE hmacState;
TPM2B_AUTH *proof;
UINT16 integritySize; 64
// Get proof value
proof = HierarchyGetProof(contextBlob->hierarchy); 67
// Start HMAC
integrity->t.size = CryptStartHMAC2B(CONTEXT_INTEGRITY_HASH_ALG,
&proof->b, &hmacState);
71
// Compute integrity size at the beginning of context blob
integritySize = sizeof(integrity->t.size) + integrity->t.size; 74
// Adding total reset counter so that the context cannot be
// used after a TPM Reset
CryptUpdateDigestInt(&hmacState, sizeof(gp.totalResetCount),
&gp.totalResetCount);
79
// If this is a ST_CLEAR object, add the clear count
// so that this contest cannot be loaded after a TPM Restart
if(contextBlob->savedHandle == 0x80000002)
CryptUpdateDigestInt(&hmacState, sizeof(gr.clearCount), &gr.clearCount); 84
// Adding sequence number to the HMAC to make sure that it doesn't
// get changed
CryptUpdateDigestInt(&hmacState, sizeof(contextBlob->sequence),
&contextBlob->sequence);
89
// Protect the handle
CryptUpdateDigestInt(&hmacState, sizeof(contextBlob->savedHandle),
&contextBlob->savedHandle); 93
94 // Adding sensitive contextData, skip the leading integrity area
CryptUpdateDigest(&hmacState, contextBlob->contextBlob.t.size - integritySize,
contextBlob->contextBlob.t.buffer + integritySize); 97
// Complete HMAC
CryptCompleteHMAC2B(&hmacState, &integrity->b); 100
101 return;
102 }
This function is used scan through the sequence object and either modify the hash state data for LIB_EXPORT or to import it into the internal format
void
SequenceDataImportExport(
OBJECT *object, // IN: the object containing the sequence data
OBJECT *exportObject, // IN/OUT: the object structure that will get
// the exported hash state
IMPORT_EXPORT direction
109 )
110 {
int count = 1;
HASH_OBJECT *internalFmt = (HASH_OBJECT *)object;
HASH_OBJECT *externalFmt = (HASH_OBJECT *)exportObject; 114
if(object->attributes.eventSeq)
count = HASH_COUNT;
for(; count; count--)
CryptHashStateImportExport(&internalFmt->state.hashState[count - 1],
externalFmt->state.hashState, direction);
120 }
7.4 Policy Command Support (Policy_spt.c)
#include "InternalRoutines.h"
#include "Policy_spt_fp.h"
#include "PolicySigned_fp.h"
#include "PolicySecret_fp.h"
#include "PolicyTicket_fp.h"
This function validates the common parameters of TPM2_PolicySiged() and TPM2_PolicySecret(). The common parameters are nonceTPM, expiration, and cpHashA.
TPM_RC
PolicyParameterChecks(
SESSION *session,
UINT64 authTimeout,
TPM2B_DIGEST *cpHashA,
TPM2B_NONCE *nonce,
TPM_RC nonceParameterNumber,
TPM_RC cpHashParameterNumber,
TPM_RC expirationParameterNumber 15 )
16 {
17 TPM_RC result; 18
// Validate that input nonceTPM is correct if present
if(nonce != NULL && nonce->t.size != 0)
21 | { | |
22 | if(!Memory2BEqual(&nonce->b, &session->nonceTPM.b)) | |
23 | return TPM_RC_NONCE + RC_PolicySigned_nonceTPM; | |
24 | } | |
25 | // If authTimeout is set (expiration != 0... | |
26 | if(authTimeout != 0) | |
27 | { | |
28 | // ...then nonce must be present | |
29 | // nonce present isn't checked in PolicyTicket | |
30 | if(nonce != NULL && nonce->t.size == 0) | |
31 | // This error says that the time has expired but it is pointing | |
32 | // at the nonceTPM value. | |
33 | return TPM_RC_EXPIRED + nonceParameterNumber; | |
34 | ||
35 | // Validate input expiration. | |
36 | // Cannot compare time if clock stop advancing. A TPM_RC_NV_UNAVAILABLE | |
37 | // or TPM_RC_NV_RATE error may be returned here. | |
38 | result = NvIsAvailable(); | |
39 | if(result != TPM_RC_SUCCESS) | |
40 | return result; | |
41 | ||
42 | if(authTimeout < go.clock) | |
43 | return TPM_RC_EXPIRED + expirationParameterNumber; | |
44 | } | |
45 | // If the cpHash is present, then check it | |
46 | if(cpHashA != NULL && cpHashA->t.size != 0) | |
47 | { | |
48 | // The cpHash input has to have the correct size | |
49 | if(cpHashA->t.size != session->u2.policyDigest.t.size) | |
50 | return TPM_RC_SIZE + cpHashParameterNumber; | |
51 | ||
52 | // If the cpHash has already been set, then this input value | |
53 | // must match the current value. | |
54 | if( session->u1.cpHash.b.size != 0 | |
55 | && !Memory2BEqual(&cpHashA->b, &session->u1.cpHash.b)) | |
56 | return TPM_RC_CPHASH; | |
57 | } | |
58 | return TPM_RC_SUCCESS; | |
59 | } |
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.
void
PolicyContextUpdate(
TPM_CC commandCode, // IN: command code
TPM2B_NAME *name, // IN: name of entity
TPM2B_NONCE *ref, // IN: the reference data
TPM2B_DIGEST *cpHash, // IN: the cpHash (optional)
UINT64 policyTimeout,
SESSION *session // IN/OUT: policy session to be updated 68 )
69 {
HASH_STATE hashState;
UINT16 policyDigestSize; 72
// Start hash
policyDigestSize = CryptStartHash(session->authHashAlg, &hashState); 75
// policyDigest size should always be the digest size of session hash algorithm.
pAssert(session->u2.policyDigest.t.size == policyDigestSize); 78
79 | // add old digest | |
80 | CryptUpdateDigest2B(&hashState, &session->u2.policyDigest.b); | |
81 | ||
82 | // add commandCode | |
83 | CryptUpdateDigestInt(&hashState, sizeof(commandCode), &commandCode); | |
84 | ||
85 | // add name if applicable | |
86 | if(name != NULL) | |
87 | CryptUpdateDigest2B(&hashState, &name->b); | |
88 | ||
89 | // Complete the digest and get the results | |
90 | CryptCompleteHash2B(&hashState, &session->u2.policyDigest.b); | |
91 | ||
92 | // Start second hash computation | |
93 | CryptStartHash(session->authHashAlg, &hashState); | |
94 | ||
95 | // add policyDigest | |
96 | CryptUpdateDigest2B(&hashState, &session->u2.policyDigest.b); | |
97 | ||
98 | // add policyRef | |
99 | if(ref != NULL) | |
100 | CryptUpdateDigest2B(&hashState, &ref->b); | |
101 | ||
102 | // Complete second digest | |
103 | CryptCompleteHash2B(&hashState, &session->u2.policyDigest.b); | |
104 | ||
105 | // Deal with the cpHash. If the cpHash value is present | |
106 | // then it would have already been checked to make sure that | |
107 | // it is compatible with the current value so all we need | |
108 | // to do here is copy it and set the iscoHashDefined attribute | |
109 | if(cpHash != NULL && cpHash->t.size != 0) | |
110 | { | |
111 | session->u1.cpHash = *cpHash; | |
112 | session->attributes.iscpHashDefined = SET; | |
113 | } | |
114 | ||
115 | // update the timeout if it is specified | |
116 | if(policyTimeout!= 0) | |
117 | { | |
118 | // If the timeout has not been set, then set it to the new value | |
119 | if(session->timeOut == 0) | |
120 | session->timeOut = policyTimeout; | |
121 | else if(session->timeOut > policyTimeout) | |
122 | session->timeOut = policyTimeout; | |
123 | } | |
124 | return; | |
125 | } |
NV Command Support (NV_spt.c)
#include "InternalRoutines.h"
#include "NV_spt_fp.h"
Common routine for validating a read Used by TPM2_NV_Read(), TPM2_NV_ReadLock() and TPM2_PolicyNV()
Error Returns | Meaning |
TPM_RC_NV_AUTHORIZATION | autHandle is not allowed to authorize read of the index |
TPM_RC_NV_LOCKED | Read locked |
TPM_RC_NV_UNINITIALIZED | Try to read an uninitialized index |
TPM_RC
NvReadAccessChecks(
TPM_HANDLE authHandle, // IN: the handle that provided the
// authorization
TPM_HANDLE nvHandle // IN: the handle of the NV index to be written 8 )
9 {
10 NV_INDEX nvIndex; 11
// Get NV index info
NvGetIndexInfo(nvHandle, &nvIndex); 14
// This check may be done before doing authorization checks as is done in this
// version of the reference code. If not done there, then uncomment the next
// three lines.
// // If data is read locked, returns an error
// if(nvIndex.publicArea.attributes.TPMA_NV_READLOCKED == SET)
// return TPM_RC_NV_LOCKED; 21
// If the authorization was provided by the owner or platform, then check
// that the attributes allow the read. If the authorization handle
// is the same as the index, then the checks were made when the authorization
// was checked..
if(authHandle == TPM_RH_OWNER) 27 {
// If Owner provided auth then ONWERWRITE must be SET
if(! nvIndex.publicArea.attributes.TPMA_NV_OWNERREAD)
return TPM_RC_NV_AUTHORIZATION; 31 }
32 else if(authHandle == TPM_RH_PLATFORM) 33 {
// If Platform provided auth then PPWRITE must be SET
if(!nvIndex.publicArea.attributes.TPMA_NV_PPREAD)
return TPM_RC_NV_AUTHORIZATION; 37 }
// If neither Owner nor Platform provided auth, make sure that it was
// provided by this index.
else if(authHandle != nvHandle)
return TPM_RC_NV_AUTHORIZATION; 42
// If the index has not been written, then the value cannot be read
// NOTE: This has to come after other access checks to make sure that
// the proper authorization is given to TPM2_NV_ReadLock()
if(nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == CLEAR)
return TPM_RC_NV_UNINITIALIZED; 48
49 return TPM_RC_SUCCESS; 50 }
Common routine for validating a write Used by TPM2_NV_Write(), TPM2_NV_Increment(), TPM2_SetBits(), and TPM2_NV_WriteLock()
Error Returns | Meaning |
TPM_RC_NV_AUTHORIZATION | Authorization fails |
TPM_RC_NV_LOCKED | Write locked |
TPM_RC
NvWriteAccessChecks(
TPM_HANDLE authHandle, // IN: the handle that provided the
// authorization
TPM_HANDLE nvHandle // IN: the handle of the NV index to be written 56 )
57 {
58 NV_INDEX nvIndex; 59
// Get NV index info
NvGetIndexInfo(nvHandle, &nvIndex); 62
// This check may be done before doing authorization checks as is done in this
// version of the reference code. If not done there, then uncomment the next
// three lines.
// // If data is write locked, returns an error
// if(nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED == SET)
// return TPM_RC_NV_LOCKED; 69
// If the authorization was provided by the owner or platform, then check
// that the attributes allow the write. If the authorization handle
// is the same as the index, then the checks were made when the authorization
// was checked..
if(authHandle == TPM_RH_OWNER) 75 {
// If Owner provided auth then ONWERWRITE must be SET
if(! nvIndex.publicArea.attributes.TPMA_NV_OWNERWRITE)
return TPM_RC_NV_AUTHORIZATION; 79 }
80 else if(authHandle == TPM_RH_PLATFORM) 81 {
// If Platform provided auth then PPWRITE must be SET
if(!nvIndex.publicArea.attributes.TPMA_NV_PPWRITE)
return TPM_RC_NV_AUTHORIZATION; 85 }
// If neither Owner nor Platform provided auth, make sure that it was
// provided by this index.
else if(authHandle != nvHandle)
return TPM_RC_NV_AUTHORIZATION; 90
91 return TPM_RC_SUCCESS; 92 }
Object Command Support (Object_spt.c)
#include "InternalRoutines.h"
#include "Object_spt_fp.h"
#include <Platform.h>
Check if the crypto sets in two public areas are equal
Error Returns | Meaning |
TPM_RC_ASYMMETRIC | mismatched parameters |
TPM_RC_HASH | mismatched name algorithm |
TPM_RC_TYPE | mismatched type |
static TPM_RC
EqualCryptSet(
TPMT_PUBLIC *publicArea1, // IN: public area 1
TPMT_PUBLIC *publicArea2 // IN: public area 2 8 )
9 {
UINT16 size1;
UINT16 size2;
BYTE params1[sizeof(TPMU_PUBLIC_PARMS)];
BYTE params2[sizeof(TPMU_PUBLIC_PARMS)];
BYTE *buffer; 15
// Compare name hash
if(publicArea1->nameAlg != publicArea2->nameAlg)
return TPM_RC_HASH; 19
// Compare algorithm
if(publicArea1->type != publicArea2->type)
return TPM_RC_TYPE; 23
// TPMU_PUBLIC_PARMS field should be identical
buffer = params1;
size1 = TPMU_PUBLIC_PARMS_Marshal(&publicArea1->parameters, &buffer,
NULL, publicArea1->type);
buffer = params2;
size2 = TPMU_PUBLIC_PARMS_Marshal(&publicArea2->parameters, &buffer,
NULL, publicArea2->type);
31
if(size1 != size2 || !MemoryEqual(params1, params2, size1))
return TPM_RC_ASYMMETRIC; 34
35 return TPM_RC_SUCCESS; 36 }
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
Return Value | Meaning |
37 | static UINT16 | |
38 | GetIV2BSize( | |
39 | TPM_HANDLE | protectorHandle // IN: the protector handle |
40 | ) | |
41 | { | |
42 | OBJECT | *protector = NULL; // Pointer to the protector object |
43 | TPM_ALG_ID | symAlg; |
44 UINT16 keyBits; 45
// Determine the symmetric algorithm and size of key
if(protectorHandle == TPM_RH_NULL) 48 {
// Use the context encryption algorithm and key size
symAlg = CONTEXT_ENCRYPT_ALG;
keyBits = CONTEXT_ENCRYPT_KEY_BITS; 52 }
53 else
54 {
protector = ObjectGet(protectorHandle);
symAlg = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
keyBits= protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym; 58 }
59
// The IV size is a UINT16 size field plus the block size of the symmetric
// algorithm
return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits); 63 }
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
static void
ComputeProtectionKeyParms(
TPM_HANDLE protectorHandle, // IN: the protector handle
TPM_ALG_ID hashAlg, // IN: hash algorithm for KDFa
TPM2B_NAME *name, // IN: name of the object
TPM2B_SEED *seedIn, // IN: optional seed for duplication blob.
// For non duplication blob, this
// parameter should be NULL
TPM_ALG_ID *symAlg, // OUT: the symmetric algorithm
UINT16 *keyBits, // OUT: the symmetric key size in bits
TPM2B_SYM_KEY *symKey // OUT: the symmetric key 75 )
76 {
TPM2B_SEED *seed = NULL;
OBJECT *protector = NULL; // Pointer to the protector 79
// Determine the algorithms for the KDF and the encryption/decryption
// For TPM_RH_NULL, using context settings
if(protectorHandle == TPM_RH_NULL) 83 {
// Use the context encryption algorithm and key size
*symAlg = CONTEXT_ENCRYPT_ALG;
symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
*keyBits = CONTEXT_ENCRYPT_KEY_BITS; 88 }
89 else
90 {
TPMT_SYM_DEF_OBJECT *symDef;
protector = ObjectGet(protectorHandle);
symDef = &protector->publicArea.parameters.asymDetail.symmetric;
*symAlg = symDef->algorithm;
*keyBits= symDef->keyBits.sym;
symKey->t.size = (*keyBits + 7) / 8; 97 }
98
// Get seed for KDF
seed = GetSeedForKDF(protectorHandle, seedIn); 101
// KDFa to generate symmetric key and IV value
KDFa(hashAlg, (TPM2B *)seed, "STORAGE", (TPM2B *)name, NULL,
symKey->t.size * 8, symKey->t.buffer, NULL); 105
106 return;
107 }
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.
static void
ComputeOuterIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE protectorHandle, // IN: The handle of the object that
// provides protection. For object, it
// is parent handle. For credential, it
// is the handle of encrypt object. For
// a Temporary Object, it is TPM_RH_NULL
TPMI_ALG_HASH hashAlg, // IN: algorithm to use for integrity
TPM2B_SEED *seedIn, // IN: an external seed may be provided for
// duplication blob. For non duplication
// blob, this parameter should be NULL
UINT32 sensitiveSize, // IN: size of the marshaled sensitive data
BYTE *sensitiveData, // IN: sensitive area
TPM2B_DIGEST *integrity // OUT: integrity
123 )
124 {
125 HMAC_STATE hmacState; 126
TPM2B_DIGEST hmacKey;
TPM2B_SEED *seed = NULL; 129
// Get seed for KDF
seed = GetSeedForKDF(protectorHandle, seedIn); 132
// Determine the HMAC key bits
hmacKey.t.size = CryptGetHashDigestSize(hashAlg); 135
// KDFa to generate HMAC key
KDFa(hashAlg, (TPM2B *)seed, "INTEGRITY", NULL, NULL,
hmacKey.t.size * 8, hmacKey.t.buffer, NULL); 139
// Start HMAC and get the size of the digest which will become the integrity
integrity->t.size = CryptStartHMAC2B(hashAlg, &hmacKey.b, &hmacState); 142
// Adding the marshaled sensitive area to the integrity value
CryptUpdateDigest(&hmacState, sensitiveSize, sensitiveData); 145
// Adding name
CryptUpdateDigest2B(&hmacState, (TPM2B *)name); 148
// Compute HMAC
CryptCompleteHMAC2B(&hmacState, &integrity->b); 151
152 return;
153 }
This function computes the integrity of an inner wrap
static void
ComputeInnerIntegrity(
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
TPM2B_NAME *name, // IN: the name of the object
UINT16 dataSize, // IN: the size of sensitive data
BYTE *sensitiveData, // IN: sensitive data
TPM2B_DIGEST *integrity // OUT: inner integrity
161 )
162 {
163 HASH_STATE hashState; 164
// Start hash and get the size of the digest which will become the integrity
integrity->t.size = CryptStartHash(hashAlg, &hashState); 167
// Adding the marshaled sensitive area to the integrity value
CryptUpdateDigest(&hashState, dataSize, sensitiveData); 170
// Adding name
CryptUpdateDigest2B(&hashState, &name->b); 173
// Compute hash
CryptCompleteHash2B(&hashState, &integrity->b); 176
177 return; 178
179 }
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
static UINT16
ProduceInnerIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
UINT16 dataSize, // IN: the size of sensitive data, excluding the
// leading integrity buffer size
BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
// it. At input, the leading bytes of this
// buffer is reserved for integrity
189 )
190 {
191 BYTE *sensitiveData; // pointer to the sensitive data 192
TPM2B_DIGEST integrity;
UINT16 integritySize;
BYTE *buffer; // Auxiliary buffer pointer 196
// sensitiveData points to the beginning of sensitive data in innerBuffer
integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
sensitiveData = innerBuffer + integritySize; 200
201 ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity); 202
// Add integrity at the beginning of inner buffer
buffer = innerBuffer;
205 | TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL); | |
206 | ||
207 | return dataSize + integritySize; | |
208 | } |
This function check integrity of inner blob
Error Returns | Meaning |
TPM_RC_INTEGRITY | if the outer blob integrity is bad |
unmarshal errors | unmarshal errors while unmarshaling integrity |
static TPM_RC
CheckInnerIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
UINT16 dataSize, // IN: the size of sensitive data, including the
// leading integrity buffer size
BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
// it
217 )
218 {
219 TPM_RC result; 220
TPM2B_DIGEST integrity;
TPM2B_DIGEST integrityToCompare;
BYTE *buffer; // Auxiliary buffer pointer
INT32 size; 225
// Unmarshal integrity
buffer = innerBuffer;
size = (INT32) dataSize;
result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
if(result == TPM_RC_SUCCESS)
231 {
// Compute integrity to compare
ComputeInnerIntegrity(hashAlg, name, (UINT16) size, buffer,
&integrityToCompare);
235
// Compare outer blob integrity
if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
result = TPM_RC_INTEGRITY;
239 }
240 return result;
241 }
This function is called by create, load, and import functions.
Return Value | Meaning |
TRUE | properties are those of a parent |
FALSE | properties are not those of a parent |
BOOL
AreAttributesForParent(
OBJECT *parentObject // IN: parent handle
245 )
246 {
// This function is only called when a parent is needed. Any
// time a "parent" is used, it must be authorized. When
// the authorization is checked, both the public and sensitive
// areas must be loaded. Just make sure...
pAssert(parentObject->attributes.publicOnly == CLEAR); 252
if(ObjectDataIsStorage(&parentObject->publicArea))
return TRUE;
else
return FALSE;
257 }
This function validates the schemes in the public area of an object. This function is called by TPM2_LoadExternal() and PublicAttributesValidation().
Error Returns | Meaning |
TPM_RC_ASYMMETRIC | non-duplicable storage key and its parent have different public parameters |
TPM_RC_ATTRIBUTES | attempt to inject sensitive data for an asymmetric key; or attempt to create a symmetric cipher key that is not a decryption key |
TPM_RC_HASH | non-duplicable storage key and its parent have different name algorithm |
TPM_RC_KDF | incorrect KDF specified for decrypting keyed hash object |
TPM_RC_KEY | invalid key size values in an asymmetric key public area |
TPM_RC_SCHEME | inconsistent attributes decrypt, sign, restricted and key's scheme ID; or hash algorithm is inconsistent with the scheme ID for keyed hash object |
TPM_RC_SYMMETRIC | a storage key with no symmetric algorithm specified; or non-storage key with symmetric algorithm different from TPM_ALG_NULL |
TPM_RC_TYPE | unexpected object type; or non-duplicable storage key and its parent have different types |
TPM_RC
SchemeChecks(
BOOL load, // IN: TRUE if load checks, FALSE if
// TPM2_Create()
TPMI_DH_OBJECT parentHandle, // IN: input parent handle
TPMT_PUBLIC *publicArea // IN: public area of the object
264 )
265 { 266
// Checks for an asymmetric key
if(CryptIsAsymAlgorithm(publicArea->type))
269 {
TPMT_ASYM_SCHEME *keyScheme;
keyScheme = &publicArea->parameters.asymDetail.scheme; 272
// An asymmetric key can't be injected
// This is only checked when creating an object
if(!load && (publicArea->objectAttributes.sensitiveDataOrigin == CLEAR))
return TPM_RC_ATTRIBUTES; 277
if(load && !CryptAreKeySizesConsistent(publicArea))
return TPM_RC_KEY; 280
// Keys that are both signing and decrypting must have TPM_ALG_NULL
// for scheme
if( publicArea->objectAttributes.sign == SET
&& publicArea->objectAttributes.decrypt == SET
&& keyScheme->scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME; 287
// A restrict sign key must have a non-NULL scheme
if( publicArea->objectAttributes.restricted == SET
&& publicArea->objectAttributes.sign == SET
&& keyScheme->scheme == TPM_ALG_NULL)
return TPM_RC_SCHEME; 293
// Keys must have a valid sign or decrypt scheme, or a TPM_ALG_NULL
// scheme
// NOTE: The unmarshaling for a public area will unmarshal based on the
// object type. If the type is an RSA key, then only RSA schemes will be
// allowed because a TPMI_ALG_RSA_SCHEME will be unmarshaled and it
// consists only of those algorithms that are allowed with an RSA key.
// This means that there is no need to again make sure that the algorithm
// is compatible with the object type.
if( keyScheme->scheme != TPM_ALG_NULL
&& ( ( publicArea->objectAttributes.sign == SET
&& !CryptIsSignScheme(keyScheme->scheme)
305 )
|| ( publicArea->objectAttributes.decrypt == SET
&& !CryptIsDecryptScheme(keyScheme->scheme)
308 )
309 )
310 )
311 return TPM_RC_SCHEME; 312
// Special checks for an ECC key
#ifdef TPM_ALG_ECC
if(publicArea->type == TPM_ALG_ECC)
316 {
TPM_ECC_CURVE curveID = publicArea->parameters.eccDetail.curveID;
const TPMT_ECC_SCHEME *curveScheme = CryptGetCurveSignScheme(curveID);
// The curveId must be valid or the unmarshaling is busted.
pAssert(curveScheme != NULL); 321
// If the curveID requires a specific scheme, then the key must select
// the same scheme
if(curveScheme->scheme != TPM_ALG_NULL)
325 {
if(keyScheme->scheme != curveScheme->scheme)
return TPM_RC_SCHEME;
// The scheme can allow any hash, or not...
if( curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
&& ( keyScheme->details.anySig.hashAlg
!= curveScheme->details.anySig.hashAlg
332 )
333 )
334 return TPM_RC_SCHEME;
335 }
// For now, the KDF must be TPM_ALG_NULL
if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
return TPM_RC_KDF;
339 }
340 #endif 341
// Checks for a storage key (restricted + decryption)
if( publicArea->objectAttributes.restricted == SET
&& publicArea->objectAttributes.decrypt == SET)
345 {
// A storage key must have a valid protection key
if( publicArea->parameters.asymDetail.symmetric.algorithm
348 == TPM_ALG_NULL)
349 return TPM_RC_SYMMETRIC; 350
// A storage key must have a null scheme
if(publicArea->parameters.asymDetail.scheme.scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME; 354
// A storage key must match its parent algorithms unless
// it is duplicable or a primary (including Temporary Primary Objects)
if( HandleGetType(parentHandle) != TPM_HT_PERMANENT
&& publicArea->objectAttributes.fixedParent == SET
359 )
360 {
// If the object to be created is a storage key, and is fixedParent,
// its crypto set has to match its parent's crypto set. TPM_RC_TYPE,
// TPM_RC_HASH or TPM_RC_ASYMMETRIC may be returned at this point
return EqualCryptSet(publicArea,
&(ObjectGet(parentHandle)->publicArea));
366 }
367 }
368 else
369 {
// Non-storage keys must have TPM_ALG_NULL for the symmetric algorithm
if( publicArea->parameters.asymDetail.symmetric.algorithm
!= TPM_ALG_NULL)
return TPM_RC_SYMMETRIC; 374
}// End of asymmetric decryption key checks
} // End of asymmetric checks 377
// Check for bit attributes
else if(publicArea->type == TPM_ALG_KEYEDHASH)
380 {
381 TPMT_KEYEDHASH_SCHEME *scheme
382 = &publicArea->parameters.keyedHashDetail.scheme;
// If both sign and decrypt are set the scheme must be TPM_ALG_NULL
// and the scheme selected when the key is used.
// If neither sign nor decrypt is set, the scheme must be TPM_ALG_NULL
// because this is a data object.
if( publicArea->objectAttributes.sign
388 == publicArea->objectAttributes.decrypt)
389 {
if(scheme->scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME;
return TPM_RC_SUCCESS;
393 }
// If this is a decryption key, make sure that is is XOR and that there
// is a KDF
else if(publicArea->objectAttributes.decrypt)
397 {
if( scheme->scheme != TPM_ALG_XOR
|| scheme->details.xor.hashAlg == TPM_ALG_NULL)
return TPM_RC_SCHEME;
if(scheme->details.xor.kdf == TPM_ALG_NULL)
return TPM_RC_KDF;
return TPM_RC_SUCCESS; 404
405 }
406 // only supported signing scheme for keyedHash object is HMAC
407 if( scheme->scheme != TPM_ALG_HMAC
408 || scheme->details.hmac.hashAlg == TPM_ALG_NULL)
409 return TPM_RC_SCHEME;
410 | |||
411 | // end of the checks for keyedHash | ||
412 | return TPM_RC_SUCCESS; | ||
413 | } | ||
414 | else if (publicArea->type == TPM_ALG_SYMCIPHER) | ||
415 | { | ||
416 | // Must be a decrypting key and may not be | a signing key | |
417 | if( publicArea->objectAttributes.decrypt | == CLEAR | |
418 | || publicArea->objectAttributes.sign == | SET | |
419 | ) | ||
420 | return TPM_RC_ATTRIBUTES; | ||
421 | } | ||
422 | else | ||
423 | return TPM_RC_TYPE; | ||
424 | |||
425 | return TPM_RC_SUCCESS; | ||
426 | } |
This function validates the values in the public area of an object. This function is called by TPM2_Create(), TPM2_Load(), and TPM2_CreatePrimary()
Error Returns | Meaning |
TPM_RC_ASYMMETRIC | non-duplicable storage key and its parent have different public parameters |
TPM_RC_ATTRIBUTES | fixedTPM, fixedParent, or encryptedDuplication attributes are inconsistent between themselves or with those of the parent object; inconsistent restricted, decrypt and sign attributes; attempt to inject sensitive data for an asymmetric key; attempt to create a symmetric cipher key that is not a decryption key |
TPM_RC_HASH | non-duplicable storage key and its parent have different name algorithm |
TPM_RC_KDF | incorrect KDF specified for decrypting keyed hash object |
TPM_RC_KEY | invalid key size values in an asymmetric key public area |
TPM_RC_SCHEME | inconsistent attributes decrypt, sign, restricted and key's scheme ID; or hash algorithm is inconsistent with the scheme ID for keyed hash object |
TPM_RC_SIZE | authPolicy size does not match digest size of the name algorithm in publicArea |
TPM_RC_SYMMETRIC | a storage key with no symmetric algorithm specified; or non-storage key with symmetric algorithm different from TPM_ALG_NULL |
TPM_RC_TYPE | unexpected object type; or non-duplicable storage key and its parent have different types |
TPM_RC
PublicAttributesValidation(
BOOL load, // IN: TRUE if load checks, FALSE if
// TPM2_Create()
TPMI_DH_OBJECT parentHandle, // IN: input parent handle
TPMT_PUBLIC *publicArea // IN: public area of the object
433 )
434 {
435 OBJECT *parentObject = NULL; 436
437 if(HandleGetType(parentHandle) != TPM_HT_PERMANENT)
438 parentObject = ObjectGet(parentHandle);
439
440 // Check authPolicy digest consistency
441 if( publicArea->authPolicy.t.size != 0
442 && ( publicArea->authPolicy.t.size
443 != CryptGetHashDigestSize(publicArea->nameAlg)
444 )
445 )
446 return TPM_RC_SIZE; 447
448 // If the parent is fixedTPM (including a Primary Object) the object must have
449 // the same value for fixedTPM and fixedParent
450 if( parentObject == NULL
451 || parentObject->publicArea.objectAttributes.fixedTPM == SET)
452 {
453 if( publicArea->objectAttributes.fixedParent
454 != publicArea->objectAttributes.fixedTPM
455 )
456 return TPM_RC_ATTRIBUTES;
457 }
458 else
459 // The parent is not fixedTPM so the object can't be fixedTPM
460 if(publicArea->objectAttributes.fixedTPM == SET)
461 return TPM_RC_ATTRIBUTES; 462
463 // A restricted object cannot be both sign and decrypt and it can't be neither
464 // sign nor decrypt
465 if ( publicArea->objectAttributes.restricted == SET
466 && ( publicArea->objectAttributes.decrypt
467 == publicArea->objectAttributes.sign)
468 )
469 return TPM_RC_ATTRIBUTES; 470
471 // A fixedTPM object can not have encryptedDuplication bit SET
472 if( publicArea->objectAttributes.fixedTPM == SET
473 && publicArea->objectAttributes.encryptedDuplication == SET)
474 return TPM_RC_ATTRIBUTES; 475
// If a parent object has fixedTPM CLEAR, the child must have the
// same encryptedDuplication value as its parent.
// Primary objects are considered to have a fixedTPM parent (the seeds).
if( ( parentObject != NULL
&& parentObject->publicArea.objectAttributes.fixedTPM == CLEAR)
// Get here if parent is not fixed TPM
&& ( publicArea->objectAttributes.encryptedDuplication
!= parentObject->publicArea.objectAttributes.encryptedDuplication
484 )
485 )
486 return TPM_RC_ATTRIBUTES; 487
488 return SchemeChecks(load, parentHandle, publicArea);
489 }
Fill in creation data for an object.
490 void
491 FillInCreationData(
492 | TPMI_DH_OBJECT | parentHandle, | // | IN: | handle of parent |
493 | TPMI_ALG_HASH | nameHashAlg, | // | IN: | name hash algorithm |
494 | TPML_PCR_SELECTION | *creationPCR, | // | IN: | PCR selection |
495 | TPM2B_DATA | *outsideData, | // | IN: | outside data |
496 | TPM2B_CREATION_DATA | *outCreation, | // | OUT: creation data for output | |
497 | TPM2B_DIGEST | *creationDigest | // | OUT: creation digest |
498 | ) | |
499 | { | |
500 | BYTE |
creationBuffer[sizeof(TPMS_CREATION_DATA)];
501 BYTE *buffer;
502 HASH_STATE hashState; 503
504 // Fill in TPMS_CREATION_DATA in outCreation 505
506 // Compute PCR digest
507 PCRComputeCurrentDigest(nameHashAlg, creationPCR,
508 &outCreation->t.creationData.pcrDigest); 509
510 // Put back PCR selection list
511 outCreation->t.creationData.pcrSelect = *creationPCR; 512
513 // Get locality
514 outCreation->t.creationData.locality
515 = LocalityGetAttributes(_plat LocalityGet()); 516
517 outCreation->t.creationData.parentNameAlg = TPM_ALG_NULL; 518
519 // If the parent is is either a primary seed or TPM_ALG_NULL, then the Name
520 // and QN of the parent are the parent's handle.
521 if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
522 {
523 BYTE *buffer = &outCreation->t.creationData.parentName.t.name[0];
524 outCreation->t.creationData.parentName.t.size =
525 TPM_HANDLE_Marshal(&parentHandle, &buffer, NULL); 526
527 // Parent qualified name of a Temporary Object is the same as parent's
528 // name
529 MemoryCopy2B(&outCreation->t.creationData.parentQualifiedName.b,
530 &outCreation->t.creationData.parentName.b,
531 sizeof(outCreation->t.creationData.parentQualifiedName.t.name)); 532
533 }
534 else // Regular object
535 {
536 OBJECT *parentObject = ObjectGet(parentHandle); 537
538 // Set name algorithm
539 outCreation->t.creationData.parentNameAlg =
540 parentObject->publicArea.nameAlg;
541 // Copy parent name
542 outCreation->t.creationData.parentName = parentObject->name; 543
544 // Copy parent qualified name
545 outCreation->t.creationData.parentQualifiedName =
546 parentObject->qualifiedName;
547 | } | |
548 | ||
549 | // Copy outside information | |
550 | outCreation->t.creationData.outsideInfo = *outsideData; | |
551 | ||
552 | // Marshal creation data to canonical form | |
553 | buffer = creationBuffer; | |
554 | outCreation->t.size = TPMS_CREATION_DATA_Marshal(&outCreation->t.creationData, | |
555 | &buffer, NULL); | |
556 | ||
557 | // Compute hash for creation field in public template | |
558 | creationDigest->t.size = CryptStartHash(nameHashAlg, &hashState); | |
559 | CryptUpdateDigest(&hashState, outCreation->t.size, creationBuffer); | |
560 | CryptCompleteHash2B(&hashState, &creationDigest->b); | |
561 | ||
562 | return; | |
563 | } |
Get a seed for KDF. The KDF for encryption and HMAC key use the same seed. It returns a pointer to the seed
564 TPM2B_SEED*
565 GetSeedForKDF(
566 TPM_HANDLE protectorHandle, // IN: the protector handle
567 TPM2B_SEED *seedIn // IN: the optional input seed
568 )
569 {
570 OBJECT *protector = NULL; // Pointer to the protector 571
572 // Get seed for encryption key. Use input seed if provided.
573 // Otherwise, using protector object's seedValue. TPM_RH_NULL is the only
574 // exception that we may not have a loaded object as protector. In such a
575 // case, use nullProof as seed.
576 if(seedIn != NULL)
577 {
578 return seedIn;
579 }
580 else
581 {
582 if(protectorHandle == TPM_RH_NULL)
583 {
584 return (TPM2B_SEED *) &gr.nullProof;
585 }
586 else
587 {
588 protector = ObjectGet(protectorHandle);
589 return (TPM2B_SEED *) &protector->sensitive.seedValue;
590 }
591 }
592 }
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
593 | UINT16 | |||||
594 | ProduceOuterWrap( | |||||
595 | TPM_HANDLE | protector, | // | IN: | The handle of the object that provides | |
596 | // | protection. For object, it is parent | ||||
597 | // | handle. For credential, it is the handle | ||||
598 | // | of encrypt object. | ||||
599 | TPM2B_NAME | *name, | // | IN: | the name of the object | |
600 | TPM_ALG_ID | hashAlg, | // | IN: | hash algorithm for outer wrap | |
601 | TPM2B_SEED | *seed, | // | IN: | an external seed may be provided for | |
602 | // | duplication blob. For non duplication | ||||
603 | // | blob, this parameter should be NULL | ||||
604 | BOOL | useIV, | // | IN: | indicate if an IV is used | |
605 | UINT16 | dataSize, | // | IN: | the size of sensitive data, excluding the | |
606 | // | leading integrity buffer size or the | ||||
607 | // | optional iv size |
608 BYTE *outerBuffer // IN/OUT: outer buffer with sensitive data in
609 | // it | |
610 | ) | |
611 | { | |
612 | TPM_ALG_ID symAlg; | |
613 | UINT16 keyBits; | |
614 | TPM2B_SYM_KEY symKey; | |
615 | TPM2B_IV ivRNG; // IV from RNG | |
616 | TPM2B_IV *iv = NULL; | |
617 | UINT16 ivSize = 0; // size of iv area, including the size field | |
618 | ||
619 | BYTE *sensitiveData; // pointer to the sensitive data | |
620 | ||
621 | TPM2B_DIGEST integrity; | |
622 | UINT16 integritySize; | |
623 | BYTE *buffer; // Auxiliary buffer pointer | |
624 | ||
625 | // Compute the beginning of sensitive data. The outer integrity should | |
626 | // always exist if this function function is called to make an outer wrap | |
627 | integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg); | |
628 | sensitiveData = outerBuffer + integritySize; | |
629 | ||
630 | // If iv is used, adjust the pointer of sensitive data and add iv before it | |
631 | if(useIV) | |
632 | { | |
633 | ivSize = GetIV2BSize(protector); | |
634 | ||
635 | // Generate IV from RNG. The iv data size should be the total IV area | |
636 | // size minus the size of size field | |
637 | ivRNG.t.size = ivSize - sizeof(UINT16); | |
638 | CryptGenerateRandom(ivRNG.t.size, ivRNG.t.buffer); | |
639 | ||
640 | // Marshal IV to buffer | |
641 | buffer = sensitiveData; | |
642 | TPM2B_IV_Marshal(&ivRNG, &buffer, NULL); | |
643 | ||
644 | // adjust sensitive data starting after IV area | |
645 | sensitiveData += ivSize; | |
646 | ||
647 | // Use iv for encryption | |
648 | iv = &ivRNG; | |
649 | } | |
650 | ||
651 | // Compute symmetric key parameters for outer buffer encryption | |
652 | ComputeProtectionKeyParms(protector, hashAlg, name, seed, | |
653 | &symAlg, &keyBits, &symKey); | |
654 | // Encrypt inner buffer in place | |
655 | CryptSymmetricEncrypt(sensitiveData, symAlg, keyBits, | |
656 | TPM_ALG_CFB, symKey.t.buffer, iv, dataSize, | |
657 | sensitiveData); | |
658 | ||
659 | // Compute outer integrity. Integrity computation includes the optional IV | |
660 | // area | |
661 | ComputeOuterIntegrity(name, protector, hashAlg, seed, dataSize + ivSize, | |
662 | outerBuffer + integritySize, &integrity); | |
663 | ||
664 | // Add integrity at the beginning of outer buffer | |
665 | buffer = outerBuffer; | |
666 | TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL); | |
667 | ||
668 | // return the total size in outer wrap | |
669 | return dataSize + integritySize + ivSize; | |
670 | ||
671 | } |
This function remove the outer wrap of a blob containing sensitive data This function performs:
check integrity of outer blob
decrypt outer blob
Error Returns | Meaning |
TPM_RC_INSUFFICIENT | error during sensitive data unmarshaling |
TPM_RC_INTEGRITY | sensitive data integrity is broken |
TPM_RC_SIZE | error during sensitive data unmarshaling |
TPM_RC_VALUE | IV size for CFB does not match the encryption algorithm block size |
672 | TPM_RC | |
673 | UnwrapOuter( | |
674 | TPM_HANDLE | protector, // IN: The handle of the object that provides |
675 | // protection. For object, it is parent | |
676 | // handle. For credential, it is the handle | |
677 | // of encrypt object. | |
678 | TPM2B_NAME | *name, // IN: the name of the object |
679 | TPM_ALG_ID | hashAlg, // IN: hash algorithm for outer wrap |
680 | TPM2B_SEED | *seed, // IN: an external seed may be provided for |
681 | // duplication blob. For non duplication | |
682 | // blob, this parameter should be NULL. | |
683 | BOOL | useIV, // IN: indicates if an IV is used |
684 | UINT16 | dataSize, // IN: size of sensitive data in outerBuffer, |
685 | // including the leading integrity buffer | |
686 | // size, and an optional iv area | |
687 | BYTE | *outerBuffer // IN/OUT: sensitive data |
688 | ) | |
689 | { | |
690 | TPM_RC | result; |
691 | TPM_ALG_ID | symAlg = TPM_ALG_NULL; |
692 | TPM2B_SYM_KEY | symKey; |
693 | UINT16 | keyBits = 0; |
694 | TPM2B_IV | ivIn; // input IV retrieved from input buffer |
695 | TPM2B_IV | *iv = NULL; |
696 | ||
697 | BYTE | *sensitiveData; // pointer to the sensitive data |
698 | ||
699 | TPM2B_DIGEST | integrityToCompare; |
700 | TPM2B_DIGEST | integrity; |
701 | INT32 | size; |
702 | ||
703 | // Unmarshal | integrity |
704 sensitiveData = outerBuffer; 705 size = (INT32) dataSize;
706 result = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size); 707 if(result == TPM_RC_SUCCESS)
708 {
709 // Compute integrity to compare
710 ComputeOuterIntegrity(name, protector, hashAlg, seed, 711 (UINT16) size, sensitiveData,
712 &integrityToCompare);
713
714 // Compare outer blob integrity
715 if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
716 return TPM_RC_INTEGRITY;
717
718 // Get the symmetric algorithm parameters used for encryption 719 ComputeProtectionKeyParms(protector, hashAlg, name, seed,
720 &symAlg, &keyBits, &symKey);
721
722 // Retrieve IV if it is used
723 if(useIV)
724 {
725 result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
726 if(result == TPM_RC_SUCCESS)
727 {
728 // The input iv size for CFB must match the encryption algorithm
729 // block size
730 if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits)) 731 result = TPM_RC_VALUE;
732 else
733 iv = &ivIn;
734 }
735 }
736 }
737 // If no errors, decrypt private in place 738 if(result == TPM_RC_SUCCESS)
739 CryptSymmetricDecrypt(sensitiveData, symAlg, keyBits, 740 TPM_ALG_CFB, symKey.t.buffer, iv,
741 (UINT16) size, sensitiveData);
742
743 return result;
744
745 }
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.
746 void
747 SensitiveToPrivate(
748 TPMT_SENSITIVE *sensitive, // IN: sensitive structure 749 TPM2B_NAME *name, // IN: the name of the object 750 TPM_HANDLE parentHandle, // IN: The parent's handle
751 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. This 752 // parameter is used when parentHandle is
753 // NULL, in which case the object is
754 // temporary.
755 TPM2B_PRIVATE *outPrivate // OUT: output private structure 756 )
757 {
758 BYTE *buffer; // Auxiliary buffer pointer
759 BYTE *sensitiveData; // pointer to the sensitive data 760 UINT16 dataSize; // data blob size
761 TPMI_ALG_HASH hashAlg; // hash algorithm for integrity 762 UINT16 integritySize;
763 UINT16 ivSize;
764
765 pAssert(name != NULL && name->t.size != 0); 766
767 // Find the hash algorithm for integrity computation 768 if(parentHandle == TPM_RH_NULL)
769 {
770 // For Temporary Object, using self name algorithm 771 hashAlg = nameAlg;
772 }
773 else
774 | { | ||
775 | // Otherwise, using parent's name algorithm | ||
776 | hashAlg = ObjectGetNameAlg(parentHandle); | ||
777 | } | ||
778 | |||
779 | // Starting of sensitive data without wrappers | ||
780 | sensitiveData = outPrivate->t.buffer; | ||
781 | |||
782 | // Compute the integrity size | ||
783 | integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg); | ||
784 | |||
785 | // Reserve space for integrity | ||
786 | sensitiveData += integritySize; | ||
787 | |||
788 | // Get iv size | ||
789 | ivSize = GetIV2BSize(parentHandle); | ||
790 | |||
791 | // Reserve space for iv | ||
792 | sensitiveData += ivSize; | ||
793 | |||
794 | // Marshal sensitive area, leaving the leading 2 bytes for size | ||
795 | buffer = sensitiveData + sizeof(UINT16); | ||
796 | dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL); | ||
797 | |||
798 | // Adding size before the data area | ||
799 | buffer = sensitiveData; | ||
800 | UINT16_Marshal(&dataSize, &buffer, NULL); | ||
801 | |||
802 | // Adjust the dataSize to include the size field | ||
803 | dataSize += sizeof(UINT16); | ||
804 | |||
805 | // Adjust the pointer to inner buffer including the iv | ||
806 | sensitiveData = outPrivate->t.buffer + ivSize; | ||
807 | |||
808 | //Produce outer wrap, including encryption and HMAC | ||
809 | outPrivate->t.size = ProduceOuterWrap(parentHandle, name, hashAlg, | NULL, | |
810 | TRUE, dataSize, outPrivate->t.buff | ||
811 | |||
812 | return; | ||
813 | } |
er);
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
Error Returns | Meaning |
TPM_RC_INTEGRITY | if the private area integrity is bad |
TPM_RC_SENSITIVE | unmarshal errors while unmarshaling TPMS_ENCRYPT from input private |
TPM_RC_VALUE | outer wrapper does not have an iV of the correct size |
814 | TPM_RC | ||
815 | PrivateToSensitive( | ||
816 | TPM2B_PRIVATE | *inPrivate, | // IN: input private structure |
817 | TPM2B_NAME | *name, | // IN: the name of the object |
818 | TPM_HANDLE parentHandle, // IN: The parent's handle | |
819 | TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It is | |
820 | // passed separately because we only pass | |
821 | // name, rather than the whole public area | |
822 | // of the object. This parameter is used in | |
823 | // the following two cases: 1. primary | |
824 | // objects. 2. duplication blob with inner | |
825 | // wrap. In other cases, this parameter | |
826 | // will be ignored | |
827 | TPMT_SENSITIVE *sensitive // OUT: sensitive structure | |
828 | ) | |
829 | { | |
830 | TPM_RC result; | |
831 | ||
832 | BYTE *buffer; | |
833 | INT32 size; | |
834 | BYTE *sensitiveData; // pointer to the sensitive data | |
835 | UINT16 dataSize; | |
836 | UINT16 dataSizeInput; | |
837 | TPMI_ALG_HASH hashAlg; // hash algorithm for integrity | |
838 | OBJECT *parent = NULL; | |
839 | ||
840 | UINT16 integritySize; | |
841 | UINT16 ivSize; | |
842 | ||
843 | // Make sure that name is provided | |
844 | pAssert(name != NULL && name->t.size != 0); | |
845 | ||
846 | // Find the hash algorithm for integrity computation | |
847 | if(parentHandle == TPM_RH_NULL) | |
848 | { | |
849 | // For Temporary Object, using self name algorithm | |
850 | hashAlg = nameAlg; | |
851 | } | |
852 | else | |
853 | { | |
854 | // Otherwise, using parent's name algorithm | |
855 | hashAlg = ObjectGetNameAlg(parentHandle); | |
856 | } | |
857 | ||
858 | // unwrap outer | |
859 | result = UnwrapOuter(parentHandle, name, hashAlg, NULL, TRUE, | |
860 | inPrivate->t.size, inPrivate->t.buffer); | |
861 | if(result != TPM_RC_SUCCESS) | |
862 | return result; | |
863 | ||
864 | // Compute the inner integrity size. | |
865 | integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg); | |
866 | ||
867 | // Get iv size | |
868 | ivSize = GetIV2BSize(parentHandle); | |
869 | ||
870 | // The starting of sensitive data and data size without outer wrapper | |
871 | sensitiveData = inPrivate->t.buffer + integritySize + ivSize; | |
872 | dataSize = inPrivate->t.size - integritySize - ivSize; | |
873 | ||
874 | // Unmarshal input data size | |
875 | buffer = sensitiveData; | |
876 | size = (INT32) dataSize; | |
877 | result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size); | |
878 | if(result == TPM_RC_SUCCESS) | |
879 | { | |
880 | if((dataSizeInput + sizeof(UINT16)) != dataSize) | |
881 | result = TPM_RC_SENSITIVE; | |
882 | else | |
883 | { |
884 | // Unmarshal sensitive buffer to sensitive structure | ||
885 | result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size); | ||
886 | if(result != TPM_RC_SUCCESS || size != 0) | ||
887 | { | ||
888 | pAssert( (parent == NULL) | ||
889 | || parent->publicArea.objectAttributes.fixedTPM == CLEAR); | ||
890 | result = TPM_RC_SENSITIVE; | ||
891 | } | ||
892 | else | ||
893 | { | ||
894 | // Always remove trailing zeros at load so that it is not necessary | ||
895 | // to check | ||
896 | // each time auth is checked. | ||
897 | MemoryRemoveTrailingZeros(&(sensitive->authValue)); | ||
898 | } | ||
899 | } | ||
900 | } | ||
901 | return result; | ||
902 | } |
This function prepare the duplication blob from the sensitive area. The operations in this function:
marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
apply inner wrap to the sensitive area if required
apply outer wrap if required
903 void
904 SensitiveToDuplicate(
905 TPMT_SENSITIVE *sensitive, // IN: sensitive structure 906 TPM2B_NAME *name, // IN: the name of the object
907 TPM_HANDLE parentHandle, // IN: The new parent's handle
908 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It 909 // is passed separately because we
910 // only pass name, rather than the
911 // whole public area of the object.
912 TPM2B_SEED *seed, // IN: the external seed. If external 913 // seed is provided with size of 0,
914 // no outer wrap should be applied
915 // to duplication blob.
916 TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the 917 // symmetric key algorithm is NULL,
918 // no inner wrap should be applied.
919 TPM2B_DATA *innerSymKey, // IN/OUT: a symmetric key may be 920 // provided to encrypt the inner
921 // wrap of a duplication blob. May
922 // be generated here if needed.
923 TPM2B_PRIVATE *outPrivate // OUT: output private structure 924 )
925 {
926 BYTE *buffer; // Auxiliary buffer pointer
927 BYTE *sensitiveData; // pointer to the sensitive data
928 TPMI_ALG_HASH outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap 929 TPMI_ALG_HASH innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap 930 UINT16 dataSize; // data blob size
931 BOOL doInnerWrap = FALSE;
932 BOOL doOuterWrap = FALSE; 933
934 // Make sure that name is provided
935 pAssert(name != NULL && name->t.size != 0); 936
937 // Make sure symDef and innerSymKey are not NULL
938 pAssert(symDef != NULL && innerSymKey != NULL); 939
940 // Starting of sensitive data without wrappers 941 sensitiveData = outPrivate->t.buffer;
942
943 // Find out if inner wrap is required 944 if(symDef->algorithm != TPM_ALG_NULL) 945 {
946 doInnerWrap = TRUE;
947 // Use self nameAlg as inner hash algorithm 948 innerHash = nameAlg;
949 // Adjust sensitive data pointer
950 sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash); 951 }
952
953 // Find out if outer wrap is required 954 if(seed->t.size != 0)
955 {
956 doOuterWrap = TRUE;
957 // Use parent nameAlg as outer hash algorithm 958 outerHash = ObjectGetNameAlg(parentHandle); 959 // Adjust sensitive data pointer
960 sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash); 961 }
962
963 // Marshal sensitive area, leaving the leading 2 bytes for size 964 buffer = sensitiveData + sizeof(UINT16);
965 dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL); 966
967 // Adding size before the data area 968 buffer = sensitiveData;
969 UINT16_Marshal(&dataSize, &buffer, NULL); 970
971 // Adjust the dataSize to include the size field 972 dataSize += sizeof(UINT16);
973
974 // Apply inner wrap for duplication blob. It includes both integrity and 975 // encryption
976 if(doInnerWrap)
977 {
BYTE *innerBuffer = NULL;
BOOL symKeyInput = TRUE;
innerBuffer = outPrivate->t.buffer;
// Skip outer integrity space
if(doOuterWrap)
innerBuffer += sizeof(UINT16) + CryptGetHashDigestSize(outerHash); 984 dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
985 innerBuffer);
986
987 // Generate inner encryption key if needed
988 if(innerSymKey->t.size == 0)
989 {
990 innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
991 CryptGenerateRandom(innerSymKey->t.size, innerSymKey->t.buffer);
992
993 // TPM generates symmetric encryption. Set the flag to FALSE 994 symKeyInput = FALSE;
995 }
996 else
997 {
998 // assume the input key size should matches the symmetric definition 999 pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1000
1001 }
1002
1003 // Encrypt inner buffer in place
1004 | CryptSymmetricEncrypt(innerBuffer, symDef->algorithm, | |
1005 | symDef->keyBits.sym, TPM_ALG_CFB, | |
1006 | innerSymKey->t.buffer, NULL, dataSize, | |
1007 | innerBuffer); | |
1008 | ||
1009 | // If the symmetric encryption key is imported, clear the buffer for | |
1010 | // output | |
1011 | if(symKeyInput) | |
1012 | innerSymKey->t.size = 0; |
1013 }
1014
1015 // Apply outer wrap for duplication blob. It includes both integrity and 1016 // encryption
1017 if(doOuterWrap)
1018 {
1019 dataSize = ProduceOuterWrap(parentHandle, name, outerHash, seed, FALSE,
1020 | ||
1021 | } | |
1022 | ||
1023 | // Data size for output | |
1024 | outPrivate->t.size = dataSize; | |
1025 | ||
1026 | return; | |
1027 | } |
dataSize, outPrivate->t.buffer);
Unwrap a duplication blob. 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
Error Returns | Meaning |
TPM_RC_INSUFFICIENT | unmarshaling sensitive data from inPrivate failed |
TPM_RC_INTEGRITY | inPrivate data integrity is broken |
TPM_RC_SIZE | unmarshaling sensitive data from inPrivate failed |
1028 | TPM_RC | ||||||
1029 | DuplicateToSensitive( | ||||||
1030 | TPM2B_PRIVATE | *inPrivate, | // | IN: | input private structure | ||
1031 | TPM2B_NAME | *name, | // | IN: | the name of the object | ||
1032 | TPM_HANDLE | parentHandle, | // | IN: | The parent's handle | ||
1033 | TPM_ALG_ID | nameAlg, | // | IN: | hash algorithm in public area. | ||
1034 | TPM2B_SEED | *seed, | // | IN: | an external seed may be provided. | ||
1035 | // | If external seed is provided with | |||||
1036 | // | size of 0, no outer wrap is | |||||
1037 | // | applied | |||||
1038 | TPMT_SYM_DEF_OBJECT | *symDef, | // | IN: | Symmetric key definition. If the | ||
1039 | // | symmetric key algorithm is NULL, | |||||
1040 | // | no inner wrap is applied | |||||
1041 | TPM2B_DATA | *innerSymKey, | // | IN: | a symmetric key may be provided | ||
1042 | // | to decrypt the inner wrap of a | |||||
1043 | // | duplication blob. | |||||
1044 | TPMT_SENSITIVE | *sensitive | // | OUT: sensitive structure | |||
1045 | ) | ||||||
1046 | { | ||||||
1047 | TPM_RC | result; | |||||
1048 |
1049 BYTE *buffer;
1050 INT32 size;
1051 BYTE *sensitiveData; // pointer to the sensitive data 1052 UINT16 dataSize;
1053 UINT16 dataSizeInput;
1054
1055 // Make sure that name is provided
1056 pAssert(name != NULL && name->t.size != 0); 1057
1058 // Make sure symDef and innerSymKey are not NULL 1059 pAssert(symDef != NULL && innerSymKey != NULL); 1060
1061 // Starting of sensitive data
1062 sensitiveData = inPrivate->t.buffer; 1063 dataSize = inPrivate->t.size;
1064
1065 // Find out if outer wrap is applied 1066 if(seed->t.size != 0)
1067 {
1068 TPMI_ALG_HASH outerHash = TPM_ALG_NULL;
1069
1070 // Use parent nameAlg as outer hash algorithm 1071 outerHash = ObjectGetNameAlg(parentHandle);
1072 result = UnwrapOuter(parentHandle, name, outerHash, seed, FALSE, 1073 dataSize, sensitiveData);
1074 if(result != TPM_RC_SUCCESS) 1075 return result;
1076
1077 // Adjust sensitive data pointer and size
1078 sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash); 1079 dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1080 }
1081 // Find out if inner wrap is applied 1082 if(symDef->algorithm != TPM_ALG_NULL) 1083 {
1084 TPMI_ALG_HASH innerHash = TPM_ALG_NULL;
1085
1086 // assume the input key size should matches the symmetric definition 1087 pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1088
1089 // Decrypt inner buffer in place
1090 CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
1091 symDef->keyBits.sym, TPM_ALG_CFB,
1092 innerSymKey->t.buffer, NULL, dataSize,
1093 sensitiveData);
1094
1095 // Use self nameAlg as inner hash algorithm 1096 innerHash = nameAlg;
1097
1098 // Check inner integrity
1099 result = CheckInnerIntegrity(name, innerHash, dataSize, sensitiveData); 1100 if(result != TPM_RC_SUCCESS)
1101 return result;
1102
1103 // Adjust sensitive data pointer and size
1104 sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash); 1105 dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1106 }
1107
1108 // Unmarshal input data size 1109 buffer = sensitiveData;
1110 size = (INT32) dataSize;
1111 result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size); 1112 if(result == TPM_RC_SUCCESS)
1113 {
1114 if((dataSizeInput + sizeof(UINT16)) != dataSize)
1115 | result = TPM_RC_SIZE; | |
1116 | else | |
1117 | { | |
1118 | // Unmarshal sensitive buffer to sensitive structure | |
1119 | result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size); | |
1120 | // if the results is OK make sure that all the data was unmarshaled | |
1121 | if(result == TPM_RC_SUCCESS && size != 0) | |
1122 | result = TPM_RC_SIZE; | |
1123 | } | |
1124 | } | |
1125 | // Always remove trailing zeros at load so that it is not necessary to check | |
1126 | // each time auth is checked. | |
1127 | if(result == TPM_RC_SUCCESS) | |
1128 | MemoryRemoveTrailingZeros(&(sensitive->authValue)); | |
1129 | return result; | |
1130 | } |
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
1131 | void |
1132 | SecretToCredential( |
1133 | TPM2B_DIGEST *secret, // IN: secret information |
1134 | TPM2B_NAME *name, // IN: the name of the object |
1135 | TPM2B_SEED *seed, // IN: an external seed. |
1136 | TPM_HANDLE protector, // IN: The protector's handle |
1137 | TPM2B_ID_OBJECT *outIDObject // OUT: output credential |
1138 | ) |
1139 | { |
1140 | BYTE *buffer; // Auxiliary buffer pointer |
1141 | BYTE *sensitiveData; // pointer to the sensitive data |
1142 | TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap |
1143 | UINT16 dataSize; // data blob size |
1144 | |
1145 | pAssert(secret != NULL && outIDObject != NULL); |
1146 | |
1147 | // use protector's name algorithm as outer hash |
1148 | outerHash = ObjectGetNameAlg(protector); |
1149 | |
1150 | // Marshal secret area to credential buffer, leave space for integrity |
1151 | sensitiveData = outIDObject->t.credential |
1152 | + sizeof(UINT16) + CryptGetHashDigestSize(outerHash); |
1153 | |
1154 | // Marshal secret area |
1155 | buffer = sensitiveData; |
1156 | dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, NULL); |
1157 | |
1158 | // Apply outer wrap |
1159 | outIDObject->t.size = ProduceOuterWrap(protector, |
1160 | name, |
1161 | outerHash, |
1162 | seed, |
1163 | FALSE, |
1164 | dataSize, |
1165 | outIDObject->t.credential); |
1166 return;
1167 }
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
Error Returns | Meaning |
TPM_RC_INSUFFICIENT | error during credential unmarshaling |
TPM_RC_INTEGRITY | credential integrity is broken |
TPM_RC_SIZE | error during credential unmarshaling |
TPM_RC_VALUE | IV size does not match the encryption algorithm block size |
1168 TPM_RC
1169 CredentialToSecret(
1170 TPM2B_ID_OBJECT *inIDObject, // IN: input credential blob 1171 TPM2B_NAME *name, // IN: the name of the object 1172 TPM2B_SEED *seed, // IN: an external seed.
1173 TPM_HANDLE protector, // IN: The protector's handle 1174 TPM2B_DIGEST *secret // OUT: secret information 1175 )
1176 {
1177 TPM_RC result;
1178 BYTE *buffer;
1179 INT32 size;
1180 TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap 1181 BYTE *sensitiveData; // pointer to the sensitive data
1182 UINT16 dataSize;
1183
1184 // use protector's name algorithm as outer hash 1185 outerHash = ObjectGetNameAlg(protector);
1186
1187 // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point 1188 result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
1189 inIDObject->t.size, inIDObject->t.credential); 1190 if(result == TPM_RC_SUCCESS)
1191 {
1192 // Compute the beginning of sensitive data 1193 sensitiveData = inIDObject->t.credential
1194 + sizeof(UINT16) + CryptGetHashDigestSize(outerHash); 1195 dataSize = inIDObject->t.size
1196 - (sizeof(UINT16) + CryptGetHashDigestSize(outerHash)); 1197
1198 // Unmarshal secret buffer to TPM2B_DIGEST structure 1199 buffer = sensitiveData;
1200 size = (INT32) dataSize;
1201 result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1202 // If there were no other unmarshaling errors, make sure that the 1203 // expected amount of data was recovered
1204 if(result == TPM_RC_SUCCESS && size != 0) 1205 return TPM_RC_SIZE;
1206 }
1207 return result;
1208 }
This file contains the functions that support command audit.
#include "InternalRoutines.h"
CommandAuditPreInstall_Init()
This function initializes the command audit list. This function is 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.
void
CommandAuditPreInstall_Init(
void
5 )
6 {
// Clear all the audit commands
MemorySet(gp.auditComands, 0x00,
((TPM_CC_LAST - TPM_CC_FIRST + 1) + 7) / 8); 10
// TPM_CC_SetCommandCodeAuditStatus always being audited
if(CommandIsImplemented(TPM_CC_SetCommandCodeAuditStatus))
CommandAuditSet(TPM_CC_SetCommandCodeAuditStatus); 14
// Set initial command audit hash algorithm to be context integrity hash
// algorithm
gp.auditHashAlg = CONTEXT_INTEGRITY_HASH_ALG; 18
// Set up audit counter to be 0
gp.auditCounter = 0; 21
// Write command audit persistent data to NV
NvWriteReserved(NV_AUDIT_COMMANDS, &gp.auditComands);
NvWriteReserved(NV_AUDIT_HASH_ALG, &gp.auditHashAlg);
NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter); 26
27 return; 28 }
This function clears the command audit digest on a TPM Reset.
void
CommandAuditStartup(
STARTUP_TYPE type // IN: start up type 32 )
33 {
34 if(type == SU_RESET)
35 {
// Reset the digest size to initialize the digest
gr.commandAuditDigest.t.size = 0; 38 }
39
40 }
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.
Return Value | Meaning |
TRUE | the command code audit status was changed |
FALSE | the command code audit status was not changed |
BOOL
CommandAuditSet(
TPM_CC commandCode // IN: command code 44 )
45 {
46 UINT32 bitPos; 47
// Only SET a bit if the corresponding command is implemented
if(CommandIsImplemented(commandCode)) 50 {
// Can't audit shutdown
if(commandCode != TPM_CC_Shutdown)
53 {
bitPos = commandCode - TPM_CC_FIRST;
if(!BitIsSet(bitPos, &gp.auditComands[0], sizeof(gp.auditComands))) 56 {
// Set bit
BitSet(bitPos, &gp.auditComands[0], sizeof(gp.auditComands));
return TRUE;
60 }
61 }
62 }
// No change
return FALSE; 65 }
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.
Return Value | Meaning |
TRUE | the command code audit status was changed |
FALSE | the command code audit status was not changed |
BOOL
CommandAuditClear(
TPM_CC commandCode // IN: command code 69 )
70 {
71 UINT32 bitPos; 72
// Do nothing if the command is not implemented
if(CommandIsImplemented(commandCode)) 75 {
// The bit associated with TPM_CC_SetCommandCodeAuditStatus() cannot be
// cleared
if(commandCode != TPM_CC_SetCommandCodeAuditStatus) 79 {
bitPos = commandCode - TPM_CC_FIRST;
if(BitIsSet(bitPos, &gp.auditComands[0], sizeof(gp.auditComands))) 82 {
// Clear bit
BitClear(bitPos, &gp.auditComands[0], sizeof(gp.auditComands));
return TRUE;
86 }
87 }
88 }
// No change
return FALSE; 91 }
This function indicates if the audit flag is SET for a command.
Return Value | Meaning |
TRUE | if command is audited |
FALSE | if command is not audited |
BOOL
CommandAuditIsRequired(
TPM_CC commandCode // IN: command code 95 )
96 {
97 UINT32 bitPos; 98
99 bitPos = commandCode - TPM_CC_FIRST; 100
// Check the bit map. If the bit is SET, command audit is required
if((gp.auditComands[bitPos/8] & (1 << (bitPos % 8))) != 0)
return TRUE;
else
return FALSE; 106
107 }
This function returns a list of commands that have their audit bit SET.
The list starts at the input commandCode.
Return Value | Meaning |
YES | if there are more command code available |
NO | all the available command code has been returned |
TPMI_YES_NO
CommandAuditCapGetCCList(
TPM_CC commandCode, // IN: start command code
UINT32 count, // IN: count of returned TPM_CC
TPML_CC *commandList // OUT: list of TPM_CC
113 )
114 {
TPMI_YES_NO more = NO;
UINT32 i; 117
// Initialize output handle list
commandList->count = 0; 120
// The maximum count of command we may return is MAX_CAP_CC
if(count > MAX_CAP_CC) count = MAX_CAP_CC; 123
// If the command code is smaller than TPM_CC_FIRST, start from TPM_CC_FIRST
if(commandCode < TPM_CC_FIRST) commandCode = TPM_CC_FIRST; 126
// Collect audit commands
for(i = commandCode; i <= TPM_CC_LAST; i++)
129 {
130 if(CommandAuditIsRequired(i))
131 {
132 if(commandList->count < count)
133 {
// If we have not filled up the return list, add this command
// code to it
commandList->commandCodes[commandList->count] = i;
commandList->count++;
138 }
139 else
140 {
// If the return list is full but we still have command
// available, report this and stop iterating
more = YES;
break;
145 }
146 }
147 }
148
149 return more; 150
151 }
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.
void
CommandAuditGetDigest(
TPM2B_DIGEST *digest // OUT: command digest
155 )
156 {
157 | TPM_CC i; | |
158 | HASH_STATE hashState; | |
159 | ||
160 | // Start hash | |
161 | digest->t.size = CryptStartHash(gp.auditHashAlg, &hashState); | |
162 | ||
163 | // Add command code | |
164 | for(i = TPM_CC_FIRST; i <= TPM_CC_LAST; i++) | |
165 | { | |
166 | if(CommandAuditIsRequired(i)) | |
167 | { | |
168 | CryptUpdateDigestInt(&hashState, sizeof(i), &i); | |
169 | } | |
170 | } | |
171 | ||
172 | // Complete hash | |
173 | CryptCompleteHash2B(&hashState, &digest->b); | |
174 | ||
175 | return; | |
176 | } |
This file contains the functions and data definitions relating to the dictionary attack logic.
Includes and Data Definitions
#define DA_C
#include "InternalRoutines.h"
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().
void
DAPreInstall_Init(
void
6 )
7 {
gp.failedTries = 0;
gp.maxTries = 3;
gp.recoveryTime = 1000; // in seconds (~16.67 minutes)
gp.lockoutRecovery = 1000; // in seconds
gp.lockOutAuthEnabled = TRUE; // Use of lockoutAuth is enabled 13
// Record persistent DA parameter changes to NV
NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
NvWriteReserved(NV_MAX_TRIES, &gp.maxTries);
NvWriteReserved(NV_RECOVERY_TIME, &gp.recoveryTime);
NvWriteReserved(NV_LOCKOUT_RECOVERY, &gp.lockoutRecovery);
NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); 20
21 return; 22 }
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.
void
DAStartup(
STARTUP_TYPE type // IN: startup type 26 )
27 {
// For TPM Reset, if lockoutRecovery is 0, enable use of lockoutAuth.
if(type == SU_RESET)
30 {
31 if(gp.lockoutRecovery == 0)
32 {
gp.lockOutAuthEnabled = TRUE;
// Record the changes to NV
NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); 36 }
37 }
38
// If DA has not been disabled and the previous shutdown is not orderly
// failedTries is not already at its maximum then increment 'failedTries'
if( gp.recoveryTime != 0
&& g_prevOrderlyState == SHUTDOWN_NONE
&& gp.failedTries < gp.maxTries) 44 {
gp.failedTries++;
// Record the change to NV
NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries); 48 }
49
// Reset self healing timers
s_selfHealTimer = g_time;
s_lockoutTimer = g_time; 53
54 return; 55 }
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.
void
DARegisterFailure(
TPM_HANDLE handle // IN: handle for failure 59 )
60 {
// Reset the timer associated with lockout if the handle is the lockout auth.
if(handle == TPM_RH_LOCKOUT)
s_lockoutTimer = g_time;
else
s_selfHealTimer = g_time;
67 return; 68 }
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.
void
DASelfHeal(
void
72 )
73 {
// Regular auth self healing logic
// If no failed authorization tries, do nothing. Otherwise, try to
// decrease failedTries
if(gp.failedTries != 0)
78 {
// if recovery time is 0, DA logic has been disabled. Clear failed tries
// immediately
if(gp.recoveryTime == 0)
82 {
gp.failedTries = 0;
// Update NV record
NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries); 86 }
87 else
88 {
89 UINT64 decreaseCount; 90
// In the unlikely event that failedTries should become larger than
// maxTries
if(gp.failedTries > gp.maxTries)
gp.failedTries = gp.maxTries; 95
// How much can failedTried be decreased
decreaseCount = ((g_time - s_selfHealTimer) / 1000) / gp.recoveryTime; 98
99 if(gp.failedTries <= (UINT32) decreaseCount)
// should not set failedTries below zero
gp.failedTries = 0;
else
gp.failedTries -= (UINT32) decreaseCount; 104
// the cast prevents overflow of the product
s_selfHealTimer += (decreaseCount * (UINT64)gp.recoveryTime) * 1000;
if(decreaseCount != 0)
// If there was a change to the failedTries, record the changes
// to NV
NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
111 }
112 }
113
// LockoutAuth self healing logic
// If lockoutAuth is enabled, do nothing. Otherwise, try to see if we
// may enable it
if(!gp.lockOutAuthEnabled)
118 {
// if lockout authorization recovery time is 0, a reboot is required to
// re-enable use of lockout authorization. Self-healing would not
// apply in this case.
if(gp.lockoutRecovery != 0)
123 | { | ||
124 | if(((g_time - s_lockoutTimer)/1000) >= gp.lockoutRecovery) | ||
125 | { | ||
126 | gp.lockOutAuthEnabled = TRUE; | ||
127 | // Record the changes to NV | ||
128 | NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 |
133 return;
134 }
This file contains the functions used for managing and accessing the hierarchy-related values.
#include "InternalRoutines.h"
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.
void
HierarchyPreInstall_Init(
void
5 )
6 {
// Allow lockout clear command
gp.disableClear = FALSE; 9
// Initialize Primary Seeds
gp.EPSeed.t.size = PRIMARY_SEED_SIZE;
CryptGenerateRandom(PRIMARY_SEED_SIZE, gp.EPSeed.t.buffer);
gp.SPSeed.t.size = PRIMARY_SEED_SIZE;
CryptGenerateRandom(PRIMARY_SEED_SIZE, gp.SPSeed.t.buffer);
gp.PPSeed.t.size = PRIMARY_SEED_SIZE;
CryptGenerateRandom(PRIMARY_SEED_SIZE, gp.PPSeed.t.buffer); 17
// Initialize owner, endorsement and lockout auth
gp.ownerAuth.t.size = 0;
gp.endorsementAuth.t.size = 0;
gp.lockoutAuth.t.size = 0; 22
// Initialize owner, endorsement, and lockout policy
gp.ownerAlg = TPM_ALG_NULL;
gp.ownerPolicy.t.size = 0;
gp.endorsementAlg = TPM_ALG_NULL;
gp.endorsementPolicy.t.size = 0;
gp.lockoutAlg = TPM_ALG_NULL;
gp.lockoutPolicy.t.size = 0;
// Initialize ehProof, shProof and phProof
gp.phProof.t.size = PROOF_SIZE;
gp.shProof.t.size = PROOF_SIZE;
gp.ehProof.t.size = PROOF_SIZE;
CryptGenerateRandom(gp.phProof.t.size, gp.phProof.t.buffer);
CryptGenerateRandom(gp.shProof.t.size, gp.shProof.t.buffer);
CryptGenerateRandom(gp.ehProof.t.size, gp.ehProof.t.buffer); 38
// Write hierarchy data to NV
NvWriteReserved(NV_DISABLE_CLEAR, &gp.disableClear);
NvWriteReserved(NV_EP_SEED, &gp.EPSeed);
NvWriteReserved(NV_SP_SEED, &gp.SPSeed);
NvWriteReserved(NV_PP_SEED, &gp.PPSeed);
NvWriteReserved(NV_OWNER_AUTH, &gp.ownerAuth);
NvWriteReserved(NV_ENDORSEMENT_AUTH, &gp.endorsementAuth);
NvWriteReserved(NV_LOCKOUT_AUTH, &gp.lockoutAuth);
NvWriteReserved(NV_OWNER_ALG, &gp.ownerAlg);
NvWriteReserved(NV_OWNER_POLICY, &gp.ownerPolicy);
NvWriteReserved(NV_ENDORSEMENT_ALG, &gp.endorsementAlg);
NvWriteReserved(NV_ENDORSEMENT_POLICY, &gp.endorsementPolicy);
NvWriteReserved(NV_LOCKOUT_ALG, &gp.lockoutAlg);
NvWriteReserved(NV_LOCKOUT_POLICY, &gp.lockoutPolicy);
NvWriteReserved(NV_PH_PROOF, &gp.phProof);
NvWriteReserved(NV_SH_PROOF, &gp.shProof);
NvWriteReserved(NV_EH_PROOF, &gp.ehProof); 56
57 return; 58 }
This function is called at TPM2_Startup() to initialize the hierarchy related values.
void
HierarchyStartup(
STARTUP_TYPE type // IN: start up type 62 )
63 {
// phEnable is SET on any startup
g_phEnable = TRUE; 66
// Reset platformAuth, platformPolicy; enable SH and EH at TPM_RESET and
// TPM_RESTART
if(type != SU_RESUME)
70 {
gc.platformAuth.t.size = 0;
gc.platformPolicy.t.size = 0; 73
// enable the storage and endorsement hierarchies and the platformNV
gc.shEnable = gc.ehEnable = gc.phEnableNV = TRUE; 76 }
77
// nullProof and nullSeed are updated at every TPM_RESET
if(type == SU_RESET)
80 {
gr.nullProof.t.size = PROOF_SIZE;
CryptGenerateRandom(gr.nullProof.t.size,
gr.nullProof.t.buffer);
gr.nullSeed.t.size = PRIMARY_SEED_SIZE;
CryptGenerateRandom(PRIMARY_SEED_SIZE, gr.nullSeed.t.buffer); 86 }
87
88 return; 89 }
This function finds the proof value associated with a hierarchy.It returns a pointer to the proof value.
TPM2B_AUTH *
HierarchyGetProof(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy constant 93 )
94 {
95 TPM2B_AUTH *auth = NULL; 96
97 switch(hierarchy)
98 {
99 case TPM_RH_PLATFORM:
// phProof for TPM_RH_PLATFORM
auth = &gp.phProof;
break;
case TPM_RH_ENDORSEMENT:
// ehProof for TPM_RH_ENDORSEMENT
auth = &gp.ehProof;
break;
case TPM_RH_OWNER:
// shProof for TPM_RH_OWNER
auth = &gp.shProof;
break;
case TPM_RH_NULL:
// nullProof for TPM_RH_NULL
auth = &gr.nullProof;
break;
default:
pAssert(FALSE);
break;
118 }
119 return auth; 120
121 }
This function returns the primary seed of a hierarchy.
TPM2B_SEED *
HierarchyGetPrimarySeed(
TPMI_RH_HIERARCHY hierarchy // IN: hierarchy
125 )
126 {
TPM2B_SEED *seed = NULL;
switch(hierarchy)
129 {
case TPM_RH_PLATFORM:
seed = &gp.PPSeed;
break;
case TPM_RH_OWNER:
seed = &gp.SPSeed;
break;
case TPM_RH_ENDORSEMENT:
seed = &gp.EPSeed;
break;
case TPM_RH_NULL:
return &gr.nullSeed;
default:
pAssert(FALSE);
break;
144 }
145 return seed;
146 }
This function checks to see if a hierarchy is enabled.
NOTE: The TPM_RH_NULL hierarchy is always enabled.
Return Value | Meaning |
TRUE | hierarchy is enabled |
FALSE | hierarchy is disabled |
147 | BOOL | |||
148 | HierarchyIsEnabled( | |||
149 | TPMI_RH_HIERARCHY hierarchy | // | IN: | hierarchy |
150 | ) | |||
151 | { | |||
152 | BOOL enabled = FALSE; | |||
153 | ||||
154 | switch(hierarchy) | |||
155 | { | |||
156 | case TPM_RH_PLATFORM: | |||
157 | enabled = g_phEnable; | |||
158 | break; | |||
159 | case TPM_RH_OWNER: | |||
160 | enabled = gc.shEnable; | |||
161 | break; | |||
162 | case TPM_RH_ENDORSEMENT: | |||
163 | enabled = gc.ehEnable; | |||
164 | break; | |||
165 | case TPM_RH_NULL: | |||
166 | enabled = TRUE; | |||
167 | break; | |||
168 | default: | |||
169 | pAssert(FALSE); | |||
170 | break; | |||
171 | } | |||
172 | return enabled; | |||
173 | } |
The NV memory is divided into two area: dynamic space for user defined NV Indices and evict objects, and reserved space for TPM persistent and state save data.
Includes, Defines and Data Definitions
#define NV_C
#include "InternalRoutines.h"
#include <Platform.h>
NV Index/evict object iterator value
typedef UINT32 NV_ITER; // type of a NV iterator
#define NV_ITER_INIT 0xFFFFFFFF // initial value to start an
// iterator
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 call to NvIsAvailable().
void
NvCheckState(void) 9 {
10 int func_return; 11
func_return = _plat IsNvAvailable();
if(func_return == 0)
14 {
15 s_NvStatus = TPM_RC_SUCCESS; 16 }
17 else if(func_return == 1)
18 {
19 s_NvStatus = TPM_RC_NV_UNAVAILABLE; 20 }
21 else
22 {
23 s_NvStatus = TPM_RC_NV_RATE; 24 }
25
26 return; 27 }
This function returns the NV availability parameter.
Error Returns | Meaning |
TPM_RC_SUCCESS | NV is available |
TPM_RC_NV_RATE | NV is unavailable because of rate limit |
TPM_RC_NV_UNAVAILABLE | NV is inaccessible |
TPM_RC
NvIsAvailable(
void
31 )
32 {
33 return s_NvStatus; 34 }
This is a wrapper for the platform function to commit pending NV writes.
BOOL
NvCommit(
void
38 )
39 {
BOOL success = (_plat NvCommit() == 0);
return success; 42 }
This function returns the max NV counter value.
static UINT64
NvReadMaxCount(
void
46 )
47 {
UINT64 countValue;
_plat NvMemoryRead(s_maxCountAddr, sizeof(UINT64), &countValue);
return countValue; 51 }
This function updates the max counter value to NV memory.
static void
NvWriteMaxCount(
UINT64 maxCount
55 )
56 {
_plat NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &maxCount);
return; 59 }
NV Index and Persistent Object Access Functions
These functions are used to access an NV Index and persistent object memory. In this implementation, the memory is simulated with RAM. The data in dynamic area is organized as a linked list, starting from address s_evictNvStart. The first 4 bytes of a node in this link list is the offset of next node, followed by the data entry. A 0-valued offset value indicates the end of the list. If the data entry area of the last node happens to reach the end of the dynamic area without space left for an additional 4 byte end marker, the end address, s_evictNvEnd, should serve as the mark of list end
This function provides a method to traverse every data entry in NV dynamic area.
To begin with, parameter iter should be initialized to NV_ITER_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.
static UINT32
NvNext(
NV_ITER *iter
63 )
64 {
65 NV_ITER currentIter; 66
// If iterator is at the beginning of list
if(*iter == NV_ITER_INIT)
69 {
// Initialize iterator
*iter = s_evictNvStart; 72 }
73
// If iterator reaches the end of NV space, or iterator indicates list end
if(*iter + sizeof(UINT32) > s_evictNvEnd || *iter == 0)
return 0;
77
// Save the current iter offset
currentIter = *iter; 80
// Adjust iter pointer pointing to next entity
// Read pointer value
_plat NvMemoryRead(*iter, sizeof(UINT32), iter); 84
85 if(*iter == 0) return 0; 86
87 return currentIter + sizeof(UINT32); // entity stores after the pointer 88 }
Function to find the end of the NV dynamic data list
static UINT32
NvGetEnd(
void
92 )
93 {
NV_ITER iter = NV_ITER_INIT;
UINT32 endAddr = s_evictNvStart;
UINT32 currentAddr; 97
while((currentAddr = NvNext(&iter)) != 0)
endAddr = currentAddr; 100
101 if(endAddr != s_evictNvStart)
102 {
// Read offset
endAddr -= sizeof(UINT32);
_plat NvMemoryRead(endAddr, sizeof(UINT32), &endAddr);
106 }
107
108 return endAddr;
109 }
This function returns the number of free octets in NV space.
static UINT32
NvGetFreeByte(
void
113 )
114 {
115 return s_evictNvEnd - NvGetEnd();
116 }
This function returns the size of an evict object in NV space
static UINT32
NvGetEvictObjectSize(
void
120 )
121 {
122 return sizeof(TPM_HANDLE) + sizeof(OBJECT) + sizeof(UINT32);
123 }
This function returns the size of a counter index in NV space.
static UINT32
NvGetCounterSize(
void
127 )
128 {
// It takes an offset field, a handle and the sizeof(NV_INDEX) and
// sizeof(UINT64) for counter data
return sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + sizeof(UINT64) + sizeof(UINT32);
132 }
This function will test if there is enough space to add a new entity.
Return Value | Meaning |
TRUE | space available |
FALSE | no enough space |
static BOOL
NvTestSpace(
UINT32 size, // IN: size of the entity to be added
BOOL isIndex // IN: TRUE if the entity is an index
137 )
138 {
139 UINT32 remainByte = NvGetFreeByte(); 140
// For NV Index, need to make sure that we do not allocate and Index if this
// would mean that the TPM cannot allocate the minimum number of evict
// objects.
if(isIndex)
145 {
// Get the number of persistent objects allocated
UINT32 persistentNum = NvCapGetPersistentNumber(); 148
// If we have not allocated the requisite number of evict objects, then we
// need to reserve space for them.
// NOTE: some of this is not written as simply as it might seem because
// the values are all unsigned and subtracting needs to be done carefully
// so that an underflow doesn't cause problems.
if(persistentNum < MIN_EVICT_OBJECTS)
155 {
UINT32 needed = (MIN_EVICT_OBJECTS - persistentNum)
* NvGetEvictObjectSize();
if(needed > remainByte)
remainByte = 0;
else
remainByte -= needed;
162 }
// if the requisite number of evict objects have been allocated then
// no need to reserve additional space
165 }
// This checks for the size of the value being added plus the index value.
// NOTE: This does not check to see if the end marker can be placed in
// memory because the end marker will not be written if it will not fit.
return (size + sizeof(UINT32) <= remainByte);
170 }
This function adds a new entity to NV.
This function requires that there is enough space to add a new entity (i.e., that NvTestSpace() has been called and the available space is at least as large as the required space).
static void
NvAdd(
UINT32 totalSize, // IN: total size needed for this entity For
// evict object, totalSize is the same as
// bufferSize. For NV Index, totalSize is
// bufferSize plus index data size
UINT32 bufferSize, // IN: size of initial buffer
BYTE *entity // IN: initial buffer
179 )
180 {
UINT32 endAddr;
UINT32 nextAddr;
UINT32 listEnd = 0; 184
// Get the end of data list
endAddr = NvGetEnd(); 187
// Calculate the value of next pointer, which is the size of a pointer +
// the entity data size
nextAddr = endAddr + sizeof(UINT32) + totalSize; 191
// Write next pointer
_plat NvMemoryWrite(endAddr, sizeof(UINT32), &nextAddr); 194
// Write entity data
_plat NvMemoryWrite(endAddr + sizeof(UINT32), bufferSize, entity); 197
// Write the end of list if it is not going to exceed the NV space
if(nextAddr + sizeof(UINT32) <= s_evictNvEnd)
_plat NvMemoryWrite(nextAddr, sizeof(UINT32), &listEnd); 201
// Set the flag so that NV changes are committed before the command completes.
g_updateNV = TRUE;
204 }
This function is used to delete an NV Index or persistent object from NV memory.
static void
NvDelete(
UINT32 entityAddr // IN: address of entity to be deleted
210 | UINT32 next; | |
211 | UINT32 entrySize; | |
212 | UINT32 entryAddr = entityAddr - sizeof(UINT32); | |
213 | UINT32 listEnd = 0; | |
214 | ||
215 | // Get the offset of the next entry. | |
216 | _plat NvMemoryRead(entryAddr, sizeof(UINT32), &next); | |
217 | ||
218 | // The size of this entry is the difference between the current entry and the | |
219 | // next entry. | |
220 | entrySize = next - entryAddr; | |
221 | ||
222 | // Move each entry after the current one to fill the freed space. | |
223 | // Stop when we have reached the end of all the indexes. There are two | |
224 | // ways to detect the end of the list. The first is to notice that there | |
225 | // is no room for anything else because we are at the end of NV. The other | |
226 | // indication is that we find an end marker. | |
227 | ||
228 | // The loop condition checks for the end of NV. | |
229 | while(next + sizeof(UINT32) <= s_evictNvEnd) | |
230 | { | |
231 | UINT32 size, oldAddr, newAddr; | |
232 | ||
233 | // Now check for the end marker | |
234 | _plat NvMemoryRead(next, sizeof(UINT32), &oldAddr); | |
235 | if(oldAddr == 0) | |
236 | break; | |
237 | ||
238 | size = oldAddr - next; | |
239 | ||
240 | // Move entry | |
241 | _plat NvMemoryMove(next, next - entrySize, size); | |
242 | ||
243 | // Update forward link | |
244 | newAddr = oldAddr - entrySize; | |
245 | _plat NvMemoryWrite(next - entrySize, sizeof(UINT32), &newAddr); | |
246 | next = oldAddr; | |
247 | } | |
248 | // Mark the end of list | |
249 | _plat NvMemoryWrite(next - entrySize, sizeof(UINT32), &listEnd); | |
250 | ||
251 | // Set the flag so that NV changes are committed before the command completes. | |
252 | g_updateNV = TRUE; | |
253 | } |
RAM-based NV Index Data Access Functions
The data layout in ram buffer is {size of(NV_handle() + data), NV_handle(), data} for each NV Index data stored in RAM.
NV storage is updated when a NV Index is added or deleted. We do NOT updated NV storage when the data is updated/
This function indicates if there is enough RAM space to add a data for a new NV Index.
Return Value | Meaning |
TRUE | space available |
FALSE | no enough space |
static BOOL
NvTestRAMSpace(
UINT32 size // IN: size of the data to be added to RAM
257 )
258 {
259 BOOL success = ( s_ramIndexSize
260 + size
261 + sizeof(TPM_HANDLE) + sizeof(UINT32)
<= RAM_INDEX_SPACE);
return success;
264 }
This function returns the offset of NV data in the RAM buffer
This function requires that NV Index is in RAM. That is, the index must be known to exist.
static UINT32
NvGetRAMIndexOffset(
TPMI_RH_NV_INDEX handle // IN: NV handle
268 )
269 {
270 UINT32 currAddr = 0; 271
272 while(currAddr < s_ramIndexSize)
273 {
TPMI_RH_NV_INDEX currHandle;
UINT32 currSize;
currHandle = * (TPM_HANDLE *) &s_ramIndex[currAddr + sizeof(UINT32)]; 277
// Found a match
if(currHandle == handle) 280
// data buffer follows the handle and size field
break;
283
currSize = * (UINT32 *) &s_ramIndex[currAddr];
currAddr += sizeof(UINT32) + currSize;
286 }
287
// We assume the index data is existing in RAM space
pAssert(currAddr < s_ramIndexSize);
return currAddr + sizeof(TPMI_RH_NV_INDEX) + sizeof(UINT32);
291 }
This function adds a new data area to RAM.
This function requires that enough free RAM space is available to add the new data.
static void
NvAddRAM(
TPMI_RH_NV_INDEX handle, // IN: NV handle
UINT32 size // IN: size of data
297 {
// Add data space at the end of reserved RAM buffer
* (UINT32 *) &s_ramIndex[s_ramIndexSize] = size + sizeof(TPMI_RH_NV_INDEX);
* (TPMI_RH_NV_INDEX *) &s_ramIndex[s_ramIndexSize + sizeof(UINT32)] = handle;
s_ramIndexSize += sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX) + size; 302
303 pAssert(s_ramIndexSize <= RAM_INDEX_SPACE); 304
// Update NV version of s_ramIndexSize
_plat NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); 307
// Write reserved RAM space to NV to reflect the newly added NV Index
_plat NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); 310
311 return;
312 }
This function is used to delete a RAM-backed NV Index data area. This function assumes the data of NV Index exists in RAM
static void
NvDeleteRAM(
TPMI_RH_NV_INDEX handle // IN: NV handle
316 )
317 {
UINT32 nodeOffset;
UINT32 nextNode;
UINT32 size; 321
322 nodeOffset = NvGetRAMIndexOffset(handle); 323
// Move the pointer back to get the size field of this node
nodeOffset -= sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX); 326
// Get node size
size = * (UINT32 *) &s_ramIndex[nodeOffset]; 329
// Get the offset of next node
nextNode = nodeOffset + sizeof(UINT32) + size; 332
// Move data
MemoryMove(s_ramIndex + nodeOffset, s_ramIndex + nextNode,
s_ramIndexSize - nextNode, s_ramIndexSize - nextNode); 336
// Update RAM size
s_ramIndexSize -= size + sizeof(UINT32); 339
// Update NV version of s_ramIndexSize
_plat NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); 342
// Write reserved RAM space to NV to reflect the newly delete NV Index
_plat NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); 345
346 return;
347 }
This function initializes the static variables used in the NV subsystem.
static void
NvInitStatic(
void
351 )
352 {
UINT16 i;
UINT32 reservedAddr; 355
s_reservedSize[NV_DISABLE_CLEAR] = sizeof(gp.disableClear);
s_reservedSize[NV_OWNER_ALG] = sizeof(gp.ownerAlg);
s_reservedSize[NV_ENDORSEMENT_ALG] = sizeof(gp.endorsementAlg);
s_reservedSize[NV_LOCKOUT_ALG] = sizeof(gp.lockoutAlg);
s_reservedSize[NV_OWNER_POLICY] = sizeof(gp.ownerPolicy);
s_reservedSize[NV_ENDORSEMENT_POLICY] = sizeof(gp.endorsementPolicy);
s_reservedSize[NV_LOCKOUT_POLICY] = sizeof(gp.lockoutPolicy);
s_reservedSize[NV_OWNER_AUTH] = sizeof(gp.ownerAuth);
s_reservedSize[NV_ENDORSEMENT_AUTH] = sizeof(gp.endorsementAuth);
s_reservedSize[NV_LOCKOUT_AUTH] = sizeof(gp.lockoutAuth);
s_reservedSize[NV_EP_SEED] = sizeof(gp.EPSeed);
s_reservedSize[NV_SP_SEED] = sizeof(gp.SPSeed);
s_reservedSize[NV_PP_SEED] = sizeof(gp.PPSeed);
s_reservedSize[NV_PH_PROOF] = sizeof(gp.phProof);
s_reservedSize[NV_SH_PROOF] = sizeof(gp.shProof);
s_reservedSize[NV_EH_PROOF] = sizeof(gp.ehProof);
s_reservedSize[NV_TOTAL_RESET_COUNT] = sizeof(gp.totalResetCount);
s_reservedSize[NV_RESET_COUNT] = sizeof(gp.resetCount);
s_reservedSize[NV_PCR_POLICIES] = sizeof(gp.pcrPolicies);
s_reservedSize[NV_PCR_ALLOCATED] = sizeof(gp.pcrAllocated);
s_reservedSize[NV_PP_LIST] = sizeof(gp.ppList);
s_reservedSize[NV_FAILED_TRIES] = sizeof(gp.failedTries);
s_reservedSize[NV_MAX_TRIES] = sizeof(gp.maxTries);
s_reservedSize[NV_RECOVERY_TIME] = sizeof(gp.recoveryTime);
s_reservedSize[NV_LOCKOUT_RECOVERY] = sizeof(gp.lockoutRecovery);
s_reservedSize[NV_LOCKOUT_AUTH_ENABLED] = sizeof(gp.lockOutAuthEnabled);
s_reservedSize[NV_ORDERLY] = sizeof(gp.orderlyState);
s_reservedSize[NV_AUDIT_COMMANDS] = sizeof(gp.auditComands);
s_reservedSize[NV_AUDIT_HASH_ALG] = sizeof(gp.auditHashAlg);
s_reservedSize[NV_AUDIT_COUNTER] = sizeof(gp.auditCounter);
s_reservedSize[NV_ALGORITHM_SET] = sizeof(gp.algorithmSet);
s_reservedSize[NV_FIRMWARE_V1] = sizeof(gp.firmwareV1);
s_reservedSize[NV_FIRMWARE_V2] = sizeof(gp.firmwareV2);
s_reservedSize[NV_ORDERLY_DATA] = sizeof(go);
s_reservedSize[NV_STATE_CLEAR] = sizeof(gc);
s_reservedSize[NV_STATE_RESET] = sizeof(gr); 392
// Initialize reserved data address. In this implementation, reserved data
// is stored at the start of NV memory
reservedAddr = 0;
for(i = 0; i < NV_RESERVE_LAST; i++)
397 {
s_reservedAddr[i] = reservedAddr;
reservedAddr += s_reservedSize[i];
400 }
401
402 // Initialize auxiliary variable space for index/evict implementation.
403 // Auxiliary variables are stored after reserved data area
404 // RAM index copy starts at the beginning
405 s_ramIndexSizeAddr = reservedAddr;
406 s_ramIndexAddr = s_ramIndexSizeAddr + sizeof(UINT32); 407
408 // Maximum counter value
409 s_maxCountAddr = s_ramIndexAddr + RAM_INDEX_SPACE; 410
411 // dynamic memory start
412 s_evictNvStart = s_maxCountAddr + sizeof(UINT64); 413
414 // dynamic memory ends at the end of NV memory
415 s_evictNvEnd = NV_MEMORY_SIZE; 416
417 return;
418 }
This function initializes the NV system at pre-install time.
This function should only be called in a manufacturing environment or in a simulation. The layout of NV memory space is an implementation choice.
419 void
420 NvInit(
421 void
422 )
423 {
424 UINT32 nullPointer = 0;
425 UINT64 zeroCounter = 0; 426
427 // Initialize static variables
428 NvInitStatic(); 429
430 // Initialize RAM index space as unused
431 _plat NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &nullPointer); 432
433 // Initialize max counter value to 0
434 _plat NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &zeroCounter); 435
436 // Initialize the next offset of the first entry in evict/index list to 0
437 _plat NvMemoryWrite(s_evictNvStart, sizeof(TPM_HANDLE), &nullPointer); 438
439 return; 440
441 }
This function is used to move reserved data from NV memory to RAM.
442 void
443 NvReadReserved(
444 NV_RESERVE type, // IN: type of reserved data
445 void *buffer // OUT: buffer receives the data.
446 )
447 {
448 // Input type should be valid
449 pAssert(type >= 0 && type < NV_RESERVE_LAST); 450
451 _plat NvMemoryRead(s_reservedAddr[type], s_reservedSize[type], buffer);
452 return;
453 }
This function is used to post a reserved data for writing to NV memory. Before the TPM completes the operation, the value will be written.
454 void
455 NvWriteReserved(
456 NV_RESERVE type, // IN: type of reserved data
457 void *buffer // IN: data buffer
458 )
459 {
460 // Input type should be valid
461 pAssert(type >= 0 && type < NV_RESERVE_LAST); 462
463 _plat NvMemoryWrite(s_reservedAddr[type], s_reservedSize[type], buffer); 464
465 // Set the flag that a NV write happens
466 g_updateNV = TRUE;
467 return;
468 }
This function reads persistent data to the RAM copy of the gp structure.
469 void
470 NvReadPersistent(
471 void
472 )
473 {
// Hierarchy persistent data
NvReadReserved(NV_DISABLE_CLEAR, &gp.disableClear);
NvReadReserved(NV_OWNER_ALG, &gp.ownerAlg);
NvReadReserved(NV_ENDORSEMENT_ALG, &gp.endorsementAlg);
NvReadReserved(NV_LOCKOUT_ALG, &gp.lockoutAlg);
NvReadReserved(NV_OWNER_POLICY, &gp.ownerPolicy);
NvReadReserved(NV_ENDORSEMENT_POLICY, &gp.endorsementPolicy);
NvReadReserved(NV_LOCKOUT_POLICY, &gp.lockoutPolicy);
NvReadReserved(NV_OWNER_AUTH, &gp.ownerAuth);
NvReadReserved(NV_ENDORSEMENT_AUTH, &gp.endorsementAuth);
NvReadReserved(NV_LOCKOUT_AUTH, &gp.lockoutAuth);
NvReadReserved(NV_EP_SEED, &gp.EPSeed);
NvReadReserved(NV_SP_SEED, &gp.SPSeed);
NvReadReserved(NV_PP_SEED, &gp.PPSeed);
NvReadReserved(NV_PH_PROOF, &gp.phProof);
NvReadReserved(NV_SH_PROOF, &gp.shProof);
NvReadReserved(NV_EH_PROOF, &gp.ehProof); 491
492 // Time persistent data
493 NvReadReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount);
494 NvReadReserved(NV_RESET_COUNT, &gp.resetCount); 495
496 // PCR persistent data
497 NvReadReserved(NV_PCR_POLICIES, &gp.pcrPolicies);
498 NvReadReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated); 499
500 // Physical Presence persistent data
501 NvReadReserved(NV_PP_LIST, &gp.ppList); 502
503 // Dictionary attack values persistent data
504 NvReadReserved(NV_FAILED_TRIES, &gp.failedTries);
505 NvReadReserved(NV_MAX_TRIES, &gp.maxTries);
506 NvReadReserved(NV_RECOVERY_TIME, &gp.recoveryTime);
507 | NvReadReserved(NV_LOCKOUT_RECOVERY, &gp.lockoutRecovery); | |
508 | NvReadReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); | |
509 | ||
510 | // Orderly State persistent data | |
511 | NvReadReserved(NV_ORDERLY, &gp.orderlyState); | |
512 | ||
513 | // Command audit values persistent data | |
514 | NvReadReserved(NV_AUDIT_COMMANDS, &gp.auditComands); | |
515 | NvReadReserved(NV_AUDIT_HASH_ALG, &gp.auditHashAlg); | |
516 | NvReadReserved(NV_AUDIT_COUNTER, &gp.auditCounter); | |
517 | ||
518 | // Algorithm selection persistent data | |
519 | NvReadReserved(NV_ALGORITHM_SET, &gp.algorithmSet); | |
520 | ||
521 | // Firmware version persistent data | |
522 | NvReadReserved(NV_FIRMWARE_V1, &gp.firmwareV1); | |
523 | NvReadReserved(NV_FIRMWARE_V2, &gp.firmwareV2); | |
524 | ||
525 | return; | |
526 | } |
NvIsPlatformPersistentHandle()
This function indicates if a handle references a persistent object in the range belonging to the platform.
Return Value | Meaning |
TRUE | handle references a platform persistent object |
FALSE | handle does not reference platform persistent object and may reference an owner persistent object either |
527 BOOL
528 NvIsPlatformPersistentHandle(
529 TPM_HANDLE handle // IN: handle
530 )
531 {
532 return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
533 }
This function indicates if a handle references a persistent object in the range belonging to the owner.
Return Value | Meaning |
TRUE | handle is owner persistent handle |
FALSE | handle is not owner persistent handle and may not be a persistent handle at all |
534 BOOL
535 NvIsOwnerPersistentHandle(
536 TPM_HANDLE handle // IN: handle
537 )
538 {
539 return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
540 }
This function returns the offset in NV of the next NV Index entry. A value of 0 indicates the end of the list.
541 | static UINT32 | |
542 | NvNextIndex( | |
543 | NV_ITER | *iter |
544 | ) | |
545 | { | |
546 | UINT32 | addr; |
547 | TPM_HANDLE | handle; |
548 | ||
549 | while((addr | = NvNext(iter)) != 0) |
550 | { | |
551 | // Read | handle |
552 _plat NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle);
553 if(HandleGetType(handle) == TPM_HT_NV_INDEX)
554 return addr;
555 }
556
557 pAssert(addr == 0);
558 return addr;
559 }
This function returns the offset in NV of the next evict object entry. A value of 0 indicates the end of the list.
560 static UINT32
561 NvNextEvict(
562 NV_ITER *iter
563 )
564 {
565 UINT32 addr;
566 TPM_HANDLE handle; 567
568 while((addr = NvNext(iter)) != 0)
569 {
570 // Read handle
571 _plat NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle);
572 if(HandleGetType(handle) == TPM_HT_PERSISTENT)
573 return addr;
574 }
575
576 pAssert(addr == 0);
577 return addr;
578 }
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.
579 static UINT32
580 NvFindHandle(
581 TPM_HANDLE handle
582 )
583 {
584 UINT32 addr;
585 NV_ITER iter = NV_ITER_INIT; 586
587 while((addr = NvNext(&iter)) != 0)
588 {
589 TPM_HANDLE entityHandle;
590 // Read handle
591 | _plat NvMemoryRead(addr, sizeof(TPM_HANDLE), &entityHandle); | |
592 | if(entityHandle == handle) | |
593 | return addr; | |
594 | } | |
595 | ||
596 | pAssert(addr == 0); | |
597 | return addr; | |
598 | } |
This function is called at _TPM_Init() to initialize the NV environment.
Return Value | Meaning |
TRUE | all NV was initialized |
FALSE | the NV containing saved state had an error and TPM2_Startup(CLEAR) is required |
599 BOOL
600 NvPowerOn(
601 void
602 )
603 {
604 int nvError = 0;
605 // If power was lost, need to re-establish the RAM data that is loaded from 606 // NV and initialize the static variables
607 if(_plat WasPowerLost(TRUE))
608 {
609 if((nvError = _plat NVEnable(0)) < 0)
610 FAIL(FATAL_ERROR_NV_UNRECOVERABLE);
611
612 NvInitStatic();
613 }
614
615 return nvError == 0;
616 }
This function is used to cause the memory containing the RAM backed NV Indices to be written to NV.
617 void
618 NvStateSave(
619 void
620 )
621 {
622 // Write RAM backed NV Index info to NV
623 // No need to save s_ramIndexSize because we save it to NV whenever it is 624 // updated.
625 _plat NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); 626
627 // Set the flag so that an NV write happens before the command completes. 628 g_updateNV = TRUE;
629
630 return;
631 }
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.
632 void
633 NvEntityStartup(
634 STARTUP_TYPE type // IN: start up type 635 )
636 {
637 NV_ITER iter = NV_ITER_INIT;
638 UINT32 currentAddr; // offset points to the current entity 639
640 // Restore RAM index data
641 _plat NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); 642 _plat NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
643
644 // If recovering from state save, do nothing 645 if(type == SU_RESUME)
646 return;
647
648 // Iterate all the NV Index to clear the locks 649 while((currentAddr = NvNextIndex(&iter)) != 0)
650 {
651 NV_INDEX nvIndex;
652 UINT32 indexAddr; // NV address points to index info 653 TPMA_NV attributes;
654
655 indexAddr = currentAddr + sizeof(TPM_HANDLE); 656
657 // Read NV Index info structure
658 _plat NvMemoryRead(indexAddr, sizeof(NV_INDEX), &nvIndex); 659 attributes = nvIndex.publicArea.attributes;
660
661 // Clear read/write lock
662 if(attributes.TPMA_NV_READLOCKED == SET)
663 attributes.TPMA_NV_READLOCKED = CLEAR;
664
665 if( attributes.TPMA_NV_WRITELOCKED == SET
666 && ( attributes.TPMA_NV_WRITTEN == CLEAR
667 || attributes.TPMA_NV_WRITEDEFINE == CLEAR
668 )
669 )
670 attributes.TPMA_NV_WRITELOCKED = CLEAR;
671
672 // Reset NV data for TPMA_NV_CLEAR_STCLEAR
673 if(attributes.TPMA_NV_CLEAR_STCLEAR == SET)
674 {
675 attributes.TPMA_NV_WRITTEN = CLEAR;
676 attributes.TPMA_NV_WRITELOCKED = CLEAR;
677 }
678
679 // Reset NV data for orderly values that are not counters
680 // NOTE: The function has already exited on a TPM Resume, so the only 681 // things being processed are TPM Restart and TPM Reset
682 if( type == SU_RESET
683 && attributes.TPMA_NV_ORDERLY == SET
684 && attributes.TPMA_NV_COUNTER == CLEAR
685 | ) | |
686 | attributes.TPMA_NV_WRITTEN = CLEAR; | |
687 | ||
688 | // Write NV Index info back if it has changed | |
689 | if(*((UINT32 *)&attributes) != *((UINT32 *)&nvIndex.publicArea.attributes)) | |
690 | { | |
691 | nvIndex.publicArea.attributes = attributes; | |
692 | _plat NvMemoryWrite(indexAddr, sizeof(NV_INDEX), &nvIndex); | |
693 | ||
694 | // Set the flag that a NV write happens | |
695 | g_updateNV = TRUE; | |
696 | } | |
697 | // Set the lower bits in an orderly counter to 1 for a non-orderly startup | |
698 | if( g_prevOrderlyState == SHUTDOWN_NONE | |
699 | && attributes.TPMA_NV_WRITTEN == SET) | |
700 | { | |
701 | if( attributes.TPMA_NV_ORDERLY == SET | |
702 | && attributes.TPMA_NV_COUNTER == SET) | |
703 | { | |
704 | TPMI_RH_NV_INDEX nvHandle; | |
705 | UINT64 counter; | |
706 | ||
707 | // Read NV handle | |
708 | _plat NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); | |
709 | ||
710 | // Read the counter value saved to NV upon the last roll over. | |
711 | // Do not use RAM backed storage for this once. | |
712 | nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = CLEAR; | |
713 | NvGetIntIndexData(nvHandle, &nvIndex, &counter); | |
714 | nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = SET; | |
715 | ||
716 | // Set the lower bits of counter to 1's | |
717 | counter |= MAX_ORDERLY_COUNT; | |
718 | ||
719 | // Write back to RAM | |
720 | NvWriteIndexData(nvHandle, &nvIndex, 0, sizeof(counter), &counter); | |
721 | ||
722 | // No write to NV because an orderly shutdown will update the | |
723 | // counters. | |
724 | ||
725 | } | |
726 | } | |
727 | } | |
728 |
729 return;
730
731 }
This set of functions provide accessing NV Index and persistent objects based using a handle for reference to the entity.
This function is used to verify that an NV Index is not defined. This is only used by TPM2_NV_DefineSpace().
Return Value | Meaning |
TRUE | the handle points to an existing NV Index |
FALSE | the handle points to a non-existent Index |
732 | BOOL |
733 | NvIsUndefinedIndex( |
734 | TPMI_RH_NV_INDEX handle // IN: handle |
735 | ) |
736 | { |
737 | UINT32 entityAddr; // offset points to the entity |
738 | |
739 | pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); |
740 | |
741 | // Find the address of index |
742 | entityAddr = NvFindHandle(handle); |
743 | |
744 | // If handle is not found, return TPM_RC_SUCCESS |
745 | if(entityAddr == 0) |
746 | return TPM_RC_SUCCESS; |
747 | |
748 | // NV Index is defined |
749 | return TPM_RC_NV_DEFINED; |
750 | } |
This function validates that a handle references a defined NV Index and that the Index is currently accessible.
Error Returns | Meaning |
TPM_RC_HANDLE | the handle points to an undefined NV Index If shEnable is CLEAR, this would include an index created using ownerAuth. If phEnableNV is CLEAR, this would include and index created using platform auth |
TPM_RC_NV_READLOCKED | Index is present but locked for reading and command does not write to the index |
TPM_RC_NV_WRITELOCKED | Index is present but locked for writing and command writes to the index |
751 TPM_RC
752 NvIndexIsAccessible(
753 TPMI_RH_NV_INDEX handle, // IN: handle
754 TPM_CC commandCode // IN: the command 755 )
756 {
757 UINT32 entityAddr; // offset points to the entity 758 NV_INDEX nvIndex; //
759
760 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 761
762 // Find the address of index
763 entityAddr = NvFindHandle(handle); 764
765 // If handle is not found, return TPM_RC_HANDLE 766 if(entityAddr == 0)
767 return TPM_RC_HANDLE;
768
769 // Read NV Index info structure
770 _plat NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 771 &nvIndex);
772
773 if(gc.shEnable == FALSE || gc.phEnableNV == FALSE) 774 {
775 // if shEnable is CLEAR, an ownerCreate NV Index should not be 776 // indicated as present
777 if(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) 778 {
779 if(gc.shEnable == FALSE)
780 return TPM_RC_HANDLE;
781 }
782 // if phEnableNV is CLEAR, a platform created Index should not 783 // be visible
784 else if(gc.phEnableNV == FALSE) 785 return TPM_RC_HANDLE;
786 }
787
788 // If the Index is write locked and this is an NV Write operation... 789 if( nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED
790 && IsWriteOperation(commandCode))
791 {
792 // then return a locked indication unless the command is TPM2_NV_WriteLock 793 if(commandCode != TPM_CC_NV_WriteLock)
794 return TPM_RC_NV_LOCKED;
795 return TPM_RC_SUCCESS;
796 }
797 // If the Index is read locked and this is an NV Read operation... 798 if( nvIndex.publicArea.attributes.TPMA_NV_READLOCKED
799 && IsReadOperation(commandCode))
800 {
801 // then return a locked indication unless the command is TPM2_NV_ReadLock 802 if(commandCode != TPM_CC_NV_ReadLock)
803 return TPM_RC_NV_LOCKED;
804 return TPM_RC_SUCCESS;
805 }
806
807 // NV Index is accessible
808 return TPM_RC_SUCCESS;
809 }
This function indicates if a handle does not reference an existing persistent object. This function requires that the handle be in the proper range for persistent objects.
Return Value | Meaning |
TRUE | handle does not reference an existing persistent object |
FALSE | handle does reference an existing persistent object |
810 | static BOOL | |
811 | NvIsUndefinedEvictHandle( | |
812 | TPM_HANDLE handle | // IN: handle |
813 | ) | |
814 | { | |
815 | UINT32 entityAddr; | // offset points to the entity |
816 | pAssert(HandleGetType(handle) | == TPM_HT_PERSISTENT); |
817 |
818 // Find the address of evict object 819 entityAddr = NvFindHandle(handle); 820
821 // If handle is not found, return TRUE 822 if(entityAddr == 0)
823 return TRUE;
824 | else | |
825 | return FALSE; | |
826 | } |
This function is used to dereference an evict object handle and get a pointer to the object.
Error Returns | Meaning |
TPM_RC_HANDLE | the handle does not point to an existing persistent object |
827 TPM_RC
828 NvGetEvictObject(
829 TPM_HANDLE handle, // IN: handle
830 OBJECT *object // OUT: object data 831 )
832 {
833 UINT32 entityAddr; // offset points to the entity 834 TPM_RC result = TPM_RC_SUCCESS;
835
836 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 837
838 // Find the address of evict object 839 entityAddr = NvFindHandle(handle); 840
841 // If handle is not found, return an error 842 if(entityAddr == 0)
843 result = TPM_RC_HANDLE; 844 else
845 // Read evict object
846 _plat NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), 847 sizeof(OBJECT),
848 object);
849
850 // whether there is an error or not, make sure that the evict
851 // status of the object is set so that the slot will get freed on exit 852 object->attributes.evict = SET;
853
854 return result;
855 }
This function is used to retrieve the contents of an NV Index.
An implementation is allowed to save the NV Index in a vendor-defined format. If the format is different from the default used by the reference code, then this function would be changed to reformat the data into the default format.
A prerequisite to calling this function is that the handle must be known to reference a defined NV Index.
856 void
857 NvGetIndexInfo(
858 TPMI_RH_NV_INDEX handle, // IN: handle
859 NV_INDEX *nvIndex // OUT: NV index structure 860 )
861 {
862 UINT32 entityAddr; // offset points to the entity 863
864 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 865
866 // Find the address of NV index
867 entityAddr = NvFindHandle(handle); 868 pAssert(entityAddr != 0);
869
870 // This implementation uses the default format so just 871 // read the data in
872 _plat NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 873 nvIndex);
874
875 return;
876 }
This function returns the value to be used when a counter index is initialized. It will scan the NV counters and find the highest value in any active counter. It will use that value as the starting point. If there are no active counters, it will use the value of the previous largest counter.
877 UINT64
878 NvInitialCounter(
879 void
880 )
881 {
882 UINT64 maxCount;
883 NV_ITER iter = NV_ITER_INIT;
884 UINT32 currentAddr;
885
886 // Read the maxCount value 887 maxCount = NvReadMaxCount(); 888
889 // Iterate all existing counters
890 while((currentAddr = NvNextIndex(&iter)) != 0)
891 {
892 TPMI_RH_NV_INDEX nvHandle;
893 NV_INDEX nvIndex;
894
895 // Read NV handle
896 _plat NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); 897
898 // Get NV Index
899 NvGetIndexInfo(nvHandle, &nvIndex);
900 if( nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET 901 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 902 {
903 UINT64 countValue;
904 // Read counter value
905 NvGetIntIndexData(nvHandle, &nvIndex, &countValue);
906 if(countValue > maxCount)
907 maxCount = countValue; 908 }
909 }
910 // Initialize the new counter value to be maxCount + 1
911 // A counter is only initialized the first time it is written. The 912 // way to write a counter is with TPM2_NV_INCREMENT(). Since the
913 // "initial" value of a defined counter is the largest count value that 914 // may have existed in this index previously, then the first use would 915 // add one to that value.
916 return maxCount;
917 }
This function is used to access the data in an NV Index. The data is returned as a byte sequence. Since counter values are kept in native format, they are converted to canonical form before being returned.
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.
918 void
919 NvGetIndexData(
920 TPMI_RH_NV_INDEX handle, // IN: handle
921 NV_INDEX *nvIndex, // IN: RAM image of index header 922 UINT32 offset, // IN: offset of NV data
923 UINT16 size, // IN: size of NV data
924 void *data // OUT: data buffer 925 )
926 {
927
928 pAssert(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET); 929
930 if( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET
931 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET) 932 {
933 // Read bit or counter data in canonical form 934 UINT64 dataInInt;
935 NvGetIntIndexData(handle, nvIndex, &dataInInt); 936 UINT64_TO_BYTE_ARRAY(dataInInt, (BYTE *)data);
937 }
938 else
939 {
940 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 941 {
942 UINT32 ramAddr;
943
944 // Get data from RAM buffer
945 ramAddr = NvGetRAMIndexOffset(handle);
946 MemoryCopy(data, s_ramIndex + ramAddr + offset, size, size); 947 }
948 else
949 {
950 UINT32 entityAddr;
951 entityAddr = NvFindHandle(handle);
952 // Get data from NV
953 // Skip NV Index info, read data buffer
954 entityAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; 955 // Read the data
956 _plat NvMemoryRead(entityAddr, size, data); 957 }
958 }
959 return;
960 }
Get data in integer format of a bit or counter NV Index.
This function requires that the NV Index is defined and that the NV Index previously has been written.
961 void
962 NvGetIntIndexData(
963 TPMI_RH_NV_INDEX handle, // IN: handle
964 NV_INDEX *nvIndex, // IN: RAM image of NV Index header
965 UINT64 *data // IN: UINT64 pointer for counter or bit 966 )
967 {
968 // Validate that index has been written and is the right type 969 pAssert( nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET
970 && ( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET 971 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET
972 | ) | |
973 | ); | |
974 | ||
975 | // bit and counter value is store in native format for TPM CPU. So we directly | |
976 | // copy the contents of NV to output data buffer | |
977 | if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) | |
978 | { | |
979 | UINT32 ramAddr; | |
980 | ||
981 | // Get data from RAM buffer | |
982 | ramAddr = NvGetRAMIndexOffset(handle); | |
983 | MemoryCopy(data, s_ramIndex + ramAddr, sizeof(*data), sizeof(*data)); | |
984 | } | |
985 | else | |
986 | { | |
987 | UINT32 entityAddr; | |
988 | entityAddr = NvFindHandle(handle); | |
989 | ||
990 | // Get data from NV | |
991 | // Skip NV Index info, read data buffer | |
992 | _plat NvMemoryRead( | |
993 | entityAddr + sizeof(TPM_HANDLE) + sizeof(NV_INDEX), | |
994 | sizeof(UINT64), data); | |
995 | } | |
996 | ||
997 | return; | |
998 | } |
This function is called to queue the write of NV Index data to persistent memory. This function requires that NV Index is defined.
Error Returns | Meaning |
TPM_RC_NV_RATE | NV is rate limiting so retry |
TPM_RC_NV_UNAVAILABLE | NV is not available |
999 TPM_RC
1000 NvWriteIndexInfo(
1001 TPMI_RH_NV_INDEX handle, // IN: handle
1002 NV_INDEX *nvIndex // IN: NV Index info to be written 1003 )
1004 {
1005 UINT32 entryAddr;
1006 TPM_RC result;
1007
1008 // Get the starting offset for the index in the RAM image of NV 1009 entryAddr = NvFindHandle(handle);
1010 pAssert(entryAddr != 0);
1011
1012 // Step over the link value
1013 entryAddr = entryAddr + sizeof(TPM_HANDLE); 1014
1015 // If the index data is actually changed, then a write to NV is required 1016 if(_plat NvIsDifferent(entryAddr, sizeof(NV_INDEX),nvIndex))
1017 {
1018 // Make sure that NV is available
1019 result = NvIsAvailable();
1020 if(result != TPM_RC_SUCCESS) 1021 return result;
1022 _plat NvMemoryWrite(entryAddr, sizeof(NV_INDEX), nvIndex); 1023 g_updateNV = TRUE;
1024 | } | |
1025 | return TPM_RC_SUCCESS; | |
1026 | } |
This function is used to write NV index data.
This function requires that the NV Index is defined, and the data is within the defined data range for the index.
Error Returns | Meaning |
TPM_RC_NV_RATE | NV is rate limiting so retry |
TPM_RC_NV_UNAVAILABLE | NV is not available |
1027 TPM_RC
1028 NvWriteIndexData(
1029 TPMI_RH_NV_INDEX handle, // IN: handle
1030 NV_INDEX *nvIndex, // IN: RAM copy of NV Index 1031 UINT32 offset, // IN: offset of NV data
1032 UINT32 size, // IN: size of NV data
1033 void *data // OUT: data buffer 1034 )
1035 {
1036 TPM_RC result;
1037 // Validate that write falls within range of the index 1038 pAssert(nvIndex->publicArea.dataSize >= offset + size); 1039
1040 // Update TPMA_NV_WRITTEN bit if necessary
1041 if(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == CLEAR) 1042 {
1043 nvIndex->publicArea.attributes.TPMA_NV_WRITTEN = SET; 1044 result = NvWriteIndexInfo(handle, nvIndex);
1045 if(result != TPM_RC_SUCCESS) 1046 return result;
1047 }
1048
1049 // Check to see if process for an orderly index is required. 1050 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1051 {
1052 UINT32 ramAddr;
1053
1054 // Write data to RAM buffer
1055 ramAddr = NvGetRAMIndexOffset(handle);
1056 MemoryCopy(s_ramIndex + ramAddr + offset, data, size, 1057 sizeof(s_ramIndex) - ramAddr - offset); 1058
1059 // NV update does not happen for orderly index. Have
1060 // to clear orderlyState to reflect that we have changed the
1061 // NV and an orderly shutdown is required. Only going to do this if we 1062 // are not processing a counter that has just rolled over
1063 if(g_updateNV == FALSE) 1064 g_clearOrderly = TRUE; 1065 }
1066 // Need to process this part if the Index isn't orderly or if it is 1067 // an orderly counter that just rolled over.
1068 if(g_updateNV || nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == CLEAR) 1069 {
1070 // Processing for an index with TPMA_NV_ORDERLY CLEAR 1071 UINT32 entryAddr = NvFindHandle(handle);
1072
1073 pAssert(entryAddr != 0);
1074
1075 // Offset into the index to the first byte of the data to be written 1076 entryAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset;
1077
1078 // If the data is actually changed, then a write to NV is required 1079 if(_plat NvIsDifferent(entryAddr, size, data))
1080 {
1081 // Make sure that NV is available
1082 result = NvIsAvailable();
1083 if(result != TPM_RC_SUCCESS) 1084 return result;
1085 _plat NvMemoryWrite(entryAddr, size, data);
1086 g_updateNV = TRUE; 1087 }
1088 }
1089 return TPM_RC_SUCCESS;
1090 }
This function is used to compute the Name of an NV 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.
1091 UINT16
1092 NvGetName(
1093 TPMI_RH_NV_INDEX handle, // IN: handle of the index 1094 NAME *name // OUT: name of the index 1095 )
1096 {
1097 UINT16 dataSize, digestSize;
1098 NV_INDEX nvIndex;
1099 BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)];
1100 BYTE *buffer;
1101 HASH_STATE hashState;
1102
1103 // Get NV public info
1104 NvGetIndexInfo(handle, &nvIndex);
1105
1106 // Marshal public area
1107 buffer = marshalBuffer;
1108 dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex.publicArea, &buffer, NULL); 1109
1110 // hash public area
1111 digestSize = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState); 1112 CryptUpdateDigest(&hashState, dataSize, marshalBuffer);
1113
1114 // Complete digest leaving room for the nameAlg
1115 CryptCompleteHash(&hashState, digestSize, &((BYTE *)name)[2]); 1116
1117 // Include the nameAlg
1118 UINT16_TO_BYTE_ARRAY(nvIndex.publicArea.nameAlg, (BYTE *)name); 1119 return digestSize + 2;
1120 }
This function is used to assign NV memory to an NV Index.
Error Returns | Meaning |
TPM_RC_NV_SPACE | insufficient NV space |
1121 TPM_RC
1122 NvDefineIndex(
1123 TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create. 1124 TPM2B_AUTH *authValue // IN: The initial authorization value 1125 )
1126 {
1127 // The buffer to be written to NV memory
1128 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(NV_INDEX)]; 1129
1130 NV_INDEX *nvIndex; // a pointer to the NV_INDEX data in 1131 // nvBuffer
1132 UINT16 entrySize; // size of entry 1133
1134 entrySize = sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + publicArea->dataSize; 1135
1136 // Check if we have enough space to create the NV Index
1137 // In this implementation, the only resource limitation is the available NV 1138 // space. Other implementation may have other limitation on counter or on 1139 // NV slot
1140 if(!NvTestSpace(entrySize, TRUE)) return TPM_RC_NV_SPACE; 1141
1142 // if the index to be defined is RAM backed, check RAM space availability 1143 // as well
1144 if(publicArea->attributes.TPMA_NV_ORDERLY == SET 1145 && !NvTestRAMSpace(publicArea->dataSize))
1146 return TPM_RC_NV_SPACE;
1147
1148 // Copy input value to nvBuffer 1149 // Copy handle
1150 * (TPM_HANDLE *) nvBuffer = publicArea->nvIndex; 1151
1152 // Copy NV_INDEX
1153 nvIndex = (NV_INDEX *) (nvBuffer + sizeof(TPM_HANDLE)); 1154 nvIndex->publicArea = *publicArea;
1155 nvIndex->authValue = *authValue; 1156
1157 // Add index to NV memory
1158 NvAdd(entrySize, sizeof(TPM_HANDLE) + sizeof(NV_INDEX), nvBuffer); 1159
1160 // If the data of NV Index is RAM backed, add the data area in RAM as well 1161 if(publicArea->attributes.TPMA_NV_ORDERLY == SET)
1162 NvAddRAM(publicArea->nvIndex, publicArea->dataSize);
1163
1164 return TPM_RC_SUCCESS;
1165 }
This function is used to assign NV memory to a persistent object.
Error Returns | Meaning |
TPM_RC_NV_HANDLE | the requested handle is already in use |
TPM_RC_NV_SPACE | insufficient NV space |
1166 | TPM_RC | ||
1167 | NvAddEvictObject( | ||
1168 | TPMI_DH_OBJECT | evictHandle, | // IN: new evict handle |
1169 OBJECT *object // IN: object to be added 1170 )
1171 {
1172 // The buffer to be written to NV memory
1173 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(OBJECT)]; 1174
1175 OBJECT *nvObject; // a pointer to the OBJECT data in 1176 // nvBuffer
1177 UINT16 entrySize; // size of entry 1178
1179 // evict handle type should match the object hierarchy 1180 pAssert( ( NvIsPlatformPersistentHandle(evictHandle) 1181 && object->attributes.ppsHierarchy == SET)
1182 || ( NvIsOwnerPersistentHandle(evictHandle) 1183 && ( object->attributes.spsHierarchy == SET
1184 || object->attributes.epsHierarchy == SET))); 1185
1186 // An evict needs 4 bytes of handle + sizeof OBJECT 1187 entrySize = sizeof(TPM_HANDLE) + sizeof(OBJECT); 1188
1189 // Check if we have enough space to add the evict object
1190 // An evict object needs 8 bytes in index table + sizeof OBJECT
1191 // In this implementation, the only resource limitation is the available NV 1192 // space. Other implementation may have other limitation on evict object 1193 // handle space
1194 if(!NvTestSpace(entrySize, FALSE)) return TPM_RC_NV_SPACE; 1195
1196 // Allocate a new evict handle
1197 if(!NvIsUndefinedEvictHandle(evictHandle))
1198 return TPM_RC_NV_DEFINED;
1199
1200 // Copy evict object to nvBuffer 1201 // Copy handle
1202 * (TPM_HANDLE *) nvBuffer = evictHandle; 1203
1204 // Copy OBJECT
1205 nvObject = (OBJECT *) (nvBuffer + sizeof(TPM_HANDLE)); 1206 *nvObject = *object;
1207
1208 // Set evict attribute and handle 1209 nvObject->attributes.evict = SET; 1210 nvObject->evictHandle = evictHandle; 1211
1212 // Add evict to NV memory
1213 NvAdd(entrySize, entrySize, nvBuffer); 1214
1215 return TPM_RC_SUCCESS;
1216
1217 }
This function will delete a NV Index or an evict object.
This function requires that the index/evict object has been defined.
1218 void
1219 NvDeleteEntity(
1220 TPM_HANDLE handle // IN: handle of entity to be deleted 1221 )
1222 {
1223 UINT32 entityAddr; // pointer to entity 1224
1225 entityAddr = NvFindHandle(handle); 1226 pAssert(entityAddr != 0);
1227
1228 if(HandleGetType(handle) == TPM_HT_NV_INDEX) 1229 {
1230 NV_INDEX nvIndex;
1231
1232 // Read the NV Index info
1233 _plat NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1234 &nvIndex);
1235
1236 // If the entity to be deleted is a counter with the maximum counter 1237 // value, record it in NV memory
1238 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET
1239 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 1240 {
1241 UINT64 countValue;
1242 UINT64 maxCount;
1243 NvGetIntIndexData(handle, &nvIndex, &countValue);
1244 maxCount = NvReadMaxCount();
1245 if(countValue > maxCount)
1246 NvWriteMaxCount(countValue);
1247 }
1248 // If the NV Index is RAM back, delete the RAM data as well 1249 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1250 NvDeleteRAM(handle);
1251 }
1252 NvDelete(entityAddr);
1253
1254 return;
1255
1256 }
This function will delete persistent objects belonging to the indicated If the storage hierarchy is selected, the function will also delete any NV Index define using ownerAuth.
1257 void
1258 NvFlushHierarchy(
1259 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed. 1260 )
1261 {
1262 NV_ITER iter = NV_ITER_INIT;
1263 UINT32 currentAddr;
1264
1265 while((currentAddr = NvNext(&iter)) != 0)
1266 {
1267 TPM_HANDLE entityHandle;
1268
1269 // Read handle information.
1270 _plat NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1271
1272 if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX) 1273 {
1274 // Handle NV Index
1275 NV_INDEX nvIndex;
1276
1277 // If flush endorsement or platform hierarchy, no NV Index would be 1278 // flushed
1279 if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM) 1280 continue;
1281 _plat NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1282 sizeof(NV_INDEX), &nvIndex);
1283
1284 // For storage hierarchy, flush OwnerCreated index
1285 if( nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) 1286 {
1287 // Delete the NV Index
1288 NvDelete(currentAddr);
1289
1290 // Re-iterate from beginning after a delete
1291 iter = NV_ITER_INIT;
1292
1293 // If the NV Index is RAM back, delete the RAM data as well
1294 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1295 NvDeleteRAM(entityHandle);
1296 }
1297 }
1298 else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT) 1299 {
1300 OBJECT object;
1301
1302 // Get evict object
1303 NvGetEvictObject(entityHandle, &object);
1304
1305 // If the evict object belongs to the hierarchy to be flushed 1306 if( ( hierarchy == TPM_RH_PLATFORM
1307 && object.attributes.ppsHierarchy == SET) 1308 || ( hierarchy == TPM_RH_OWNER
1309 && object.attributes.spsHierarchy == SET) 1310 || ( hierarchy == TPM_RH_ENDORSEMENT
1311 && object.attributes.epsHierarchy == SET) 1312 )
1313 {
1314 // Delete the evict object
1315 NvDelete(currentAddr);
1316
1317 // Re-iterate from beginning after a delete
1318 iter = NV_ITER_INIT;
1319 }
1320 }
1321 else
1322 {
1323 pAssert(FALSE);
1324 }
1325 }
1326
1327 return;
1328 }
This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV Indices that have TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock().
1329 void
1330 NvSetGlobalLock(
1331 void
1332 )
1333 {
1334 NV_ITER iter = NV_ITER_INIT;
1335 UINT32 currentAddr;
1336
1337 // Check all Indices
1338 while((currentAddr = NvNextIndex(&iter)) != 0)
1339 {
1340 NV_INDEX nvIndex;
1341
1342 // Read the index data
1343 _plat NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1344 sizeof(NV_INDEX), &nvIndex);
1345
1346 // See if it should be locked
1347 if(nvIndex.publicArea.attributes.TPMA_NV_GLOBALLOCK == SET) 1348 {
1349
1350 // if so, lock it
1351 nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED = SET; 1352
1353 _plat NvMemoryWrite(currentAddr + sizeof(TPM_HANDLE), 1354 sizeof(NV_INDEX), &nvIndex);
1355 // Set the flag that a NV write happens
1356 g_updateNV = TRUE; 1357 }
1358 }
1359
1360 return;
1361
1362 }
Sort a handle into handle list in ascending order. The total handle number in the list should not exceed MAX_CAP_HANDLES
1363 static void
1364 InsertSort(
1365 TPML_HANDLE *handleList, // IN/OUT: sorted handle list
1366 UINT32 count, // IN: maximum count in the handle list 1367 TPM_HANDLE entityHandle // IN: handle to be inserted
1368 )
1369 {
1370 UINT32 i, j;
1371 UINT32 originalCount;
1372
1373 // For a corner case that the maximum count is 0, do nothing 1374 if(count == 0) return;
1375
1376 // For empty list, add the handle at the beginning and return 1377 if(handleList->count == 0)
1378 {
1379 handleList->handle[0] = entityHandle;
1380 handleList->count++;
1381 return;
1382 }
1383
1384 // Check if the maximum of the list has been reached 1385 originalCount = handleList->count;
1386 if(originalCount < count)
1387 handleList->count++;
1388
1389 // Insert the handle to the list 1390 for(i = 0; i < originalCount; i++) 1391 {
1392 if(handleList->handle[i] > entityHandle)
1393 {
1394 for(j = handleList->count - 1; j > i; j--)
1395 {
1396 handleList->handle[j] = handleList->handle[j-1]; 1397 }
1398 break;
1399 }
1400 }
1401 | ||
1402 | // If a slot was found, insert the handle in this position | |
1403 | if(i < originalCount || handleList->count > originalCount) | |
1404 | handleList->handle[i] = entityHandle; | |
1405 | ||
1406 | return; | |
1407 | } |
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.
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
1408 TPMI_YES_NO
1409 NvCapGetPersistent(
1410 TPMI_DH_OBJECT handle, // IN: start handle
1411 UINT32 count, // IN: maximum number of returned handle 1412 TPML_HANDLE *handleList // OUT: list of handle
1413 )
1414 {
1415 TPMI_YES_NO more = NO;
1416 NV_ITER iter = NV_ITER_INIT;
1417 UINT32 currentAddr;
1418
1419 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1420
1421 // Initialize output handle list 1422 handleList->count = 0;
1423
1424 // The maximum count of handles we may return is MAX_CAP_HANDLES 1425 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1426
1427 while((currentAddr = NvNextEvict(&iter)) != 0)
1428 {
1429 TPM_HANDLE entityHandle;
1430
1431 // Read handle information.
1432 _plat NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1433
1434 // Ignore persistent handles that have values less than the input handle 1435 if(entityHandle < handle)
1436 continue;
1437
1438 // if the handles in the list have reached the requested count, and there 1439 // are still handles need to be inserted, indicate that there are more.
1440 if(handleList->count == count) 1441 more = YES;
1442
1443 // A handle with a value larger than start handle is a candidate
1444 // for return. Insert sort it to the return list. Insert sort algorithm 1445 // is chosen here for simplicity based on the assumption that the total 1446 // number of NV Indices is small. For an implementation that may allow 1447 // large number of NV Indices, a more efficient sorting algorithm may be 1448 // used here.
1449 InsertSort(handleList, count, entityHandle); 1450
1451 | } | |
1452 | return more; | |
1453 | } |
This function returns a list of handles of NV Indices, starting from handle. Handle must be in the range of NV Indices, but does not have to reference an existing NV Index.
Return Value | Meaning |
YES | if there are more handles to report |
NO | all the available handles has been reported |
1454 TPMI_YES_NO
1455 NvCapGetIndex(
1456 TPMI_DH_OBJECT handle, // IN: start handle
1457 UINT32 count, // IN: maximum number of returned handle 1458 TPML_HANDLE *handleList // OUT: list of handle
1459 )
1460 {
1461 TPMI_YES_NO more = NO;
1462 NV_ITER iter = NV_ITER_INIT;
1463 UINT32 currentAddr;
1464
1465 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1466
1467 // Initialize output handle list 1468 handleList->count = 0;
1469
1470 // The maximum count of handles we may return is MAX_CAP_HANDLES 1471 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1472
1473 while((currentAddr = NvNextIndex(&iter)) != 0)
1474 {
1475 TPM_HANDLE entityHandle;
1476
1477 // Read handle information.
1478 _plat NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1479
1480 // Ignore index handles that have values less than the 'handle' 1481 if(entityHandle < handle)
1482 continue;
1483
1484 // if the count of handles in the list has reached the requested count, 1485 // and there are still handles to report, set more.
1486 if(handleList->count == count) 1487 more = YES;
1488
1489 // A handle with a value larger than start handle is a candidate
1490 // for return. Insert sort it to the return list. Insert sort algorithm 1491 // is chosen here for simplicity based on the assumption that the total 1492 // number of NV Indices is small. For an implementation that may allow 1493 // large number of NV Indices, a more efficient sorting algorithm may be 1494 // used here.
1495 InsertSort(handleList, count, entityHandle); 1496 }
1497 return more;
1498 }
This function returns the count of NV Indexes currently defined.
1499 UINT32
1500 NvCapGetIndexNumber(
1501 void
1502 )
1503 {
1504 UINT32 num = 0;
1505 NV_ITER iter = NV_ITER_INIT;
1506
1507 while(NvNextIndex(&iter) != 0) num++;
1508
1509 return num;
1510 }
Function returns the count of persistent objects currently in NV memory.
1511 UINT32
1512 NvCapGetPersistentNumber(
1513 void
1514 )
1515 {
1516 UINT32 num = 0;
1517 NV_ITER iter = NV_ITER_INIT;
1518
1519 while(NvNextEvict(&iter) != 0) num++;
1520
1521 return num;
1522 }
This function returns an estimate of the number of additional persistent objects that could be loaded into NV memory.
1523 UINT32
1524 NvCapGetPersistentAvail(
1525 void
1526 )
1527 {
1528 UINT32 availSpace;
1529 UINT32 objectSpace;
1530
1531 // Compute the available space in NV storage 1532 availSpace = NvGetFreeByte();
1533
1534 // Get the space needed to add a persistent object to NV storage 1535 objectSpace = NvGetEvictObjectSize();
1536
1537 return availSpace / objectSpace; 1538 }
Get the number of defined NV Indexes that have NV TPMA_NV_COUNTER attribute SET.
1539 UINT32
1540 NvCapGetCounterNumber(
1541 void
1542 )
1543 {
1544 NV_ITER iter = NV_ITER_INIT;
1545 UINT32 currentAddr;
1546 UINT32 num = 0;
1547
1548 while((currentAddr = NvNextIndex(&iter)) != 0)
1549 {
1550 NV_INDEX nvIndex;
1551
1552 // Get NV Index info
1553 _plat NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1554 sizeof(NV_INDEX), &nvIndex);
1555 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET) num++; 1556 }
1557
1558 return num;
1559 }
This function returns an estimate of the number of additional counter type NV Indices that can be defined.
1560 UINT32
1561 NvCapGetCounterAvail(
1562 void
1563 )
1564 {
1565 UINT32 availNVSpace;
1566 UINT32 availRAMSpace;
1567 UINT32 counterNVSpace;
1568 UINT32 counterRAMSpace;
1569 UINT32 persistentNum = NvCapGetPersistentNumber(); 1570
1571 // Get the available space in NV storage 1572 availNVSpace = NvGetFreeByte();
1573
1574 if (persistentNum < MIN_EVICT_OBJECTS) 1575 {
1576 // Some space have to be reserved for evict object. Adjust availNVSpace. 1577 UINT32 reserved = (MIN_EVICT_OBJECTS - persistentNum)
1578 * NvGetEvictObjectSize();
1579 if (reserved > availNVSpace) 1580 availNVSpace = 0;
1581 else
1582 availNVSpace -= reserved; 1583 }
1584
1585 // Get the space needed to add a counter index to NV storage 1586 counterNVSpace = NvGetCounterSize();
1587
1588 // Compute the available space in RAM
1589 availRAMSpace = RAM_INDEX_SPACE - s_ramIndexSize; 1590
1591 // Compute the space needed to add a counter index to RAM storage
1592 // It takes an size field, a handle and sizeof(UINT64) for counter data 1593 counterRAMSpace = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(UINT64); 1594
1595 // Return the min of counter number in NV and in RAM
1596 if(availNVSpace / counterNVSpace > availRAMSpace / counterRAMSpace) 1597 return availRAMSpace / counterRAMSpace;
1598 | else | |
1599 | return availNVSpace / counterNVSpace; | |
1600 | } |
This file contains the functions that manage the object store of the TPM.
Includes and Data Definitions
#define OBJECT_C
#include "InternalRoutines.h"
#include <Platform.h>
This function is called at TPM2_Startup() to initialize the object subsystem.
void
ObjectStartup(
void
7 )
8 {
9 UINT32 i; 10
// object slots initialization
for(i = 0; i < MAX_LOADED_OBJECTS; i++) 13 {
//Set the slot to not occupied
s_objects[i].occupied = FALSE; 16 }
17 return; 18 }
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().
void
ObjectCleanupEvict(
void
22 )
23 {
24 UINT32 i; 25
// This has to be iterated because a command may have two handles
// and they may both be persistent.
// This could be made to be more efficient so that a search is not needed.
for(i = 0; i < MAX_LOADED_OBJECTS; i++) 30 {
// If an object is a temporary evict object, flush it from slot
if(s_objects[i].object.entity.attributes.evict == SET)
s_objects[i].occupied = FALSE; 34 }
35
36 return; 37 }
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.
Return Value | Meaning |
TRUE | if the handle references a loaded object |
FALSE | if the handle is not an object handle, or it does not reference to a loaded object |
BOOL
ObjectIsPresent(
TPMI_DH_OBJECT handle // IN: handle to be checked 41 )
42 {
43 UINT32 slotIndex; // index of object slot 44
45 pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); 46
// The index in the loaded object array is found by subtracting the first
// object handle number from the input handle number. If the indicated
// slot is occupied, then indicate that there is already is a loaded
// object associated with the handle.
slotIndex = handle - TRANSIENT_FIRST;
if(slotIndex >= MAX_LOADED_OBJECTS)
return FALSE; 54
55 return s_objects[slotIndex].occupied; 56 }
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.
Return Value | Meaning |
TRUE | object is an HMAC, hash, or event sequence object |
FALSE | object is not an HMAC, hash, or event sequence object |
BOOL
ObjectIsSequence(
OBJECT *object // IN: handle to be checked 60 )
61 {
pAssert (object != NULL);
if( object->attributes.hmacSeq == SET
|| object->attributes.hashSeq == SET
|| object->attributes.eventSeq == SET)
return TRUE;
else
return FALSE; 69 }
This function is used to find the object structure associated with a handle. This function requires that handle references a loaded object.
OBJECT*
ObjectGet(
TPMI_DH_OBJECT handle // IN: handle of the object 73 )
74 {
pAssert( handle >= TRANSIENT_FIRST
&& handle - TRANSIENT_FIRST < MAX_LOADED_OBJECTS);
pAssert(s_objects[handle - TRANSIENT_FIRST].occupied == TRUE); 78
// In this implementation, the handle is determined by the slot occupied by the
// object.
return &s_objects[handle - TRANSIENT_FIRST].object.entity; 82 }
This function is used to access the Name of the object. In this implementation, the Name is computed when the object is loaded and is saved in the internal representation of the object. This function copies the Name data from the object into the buffer at name and returns the number of octets copied.
This function requires that handle references a loaded object.
UINT16
ObjectGetName(
TPMI_DH_OBJECT handle, // IN: handle of the object
NAME *name // OUT: name of the object 87 )
88 {
OBJECT *object = ObjectGet(handle);
if(object->publicArea.nameAlg == TPM_ALG_NULL)
return 0;
92
// Copy the Name data to the output
MemoryCopy(name, object->name.t.name, object->name.t.size, sizeof(NAME));
return object->name.t.size; 96 }
This function is used to get the Name algorithm of a object. This function requires that handle references a loaded object.
TPMI_ALG_HASH
ObjectGetNameAlg(
TPMI_DH_OBJECT handle // IN: handle of the object
100 )
101 {
102 OBJECT *object = ObjectGet(handle); 103
104 return object->publicArea.nameAlg;
105 }
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.
void
ObjectGetQualifiedName(
TPMI_DH_OBJECT handle, // IN: handle of the object
TPM2B_NAME *qualifiedName // OUT: qualified name of the object
110 )
111 {
OBJECT *object = ObjectGet(handle);
if(object->publicArea.nameAlg == TPM_ALG_NULL)
qualifiedName->t.size = 0;
else
// Copy the name
*qualifiedName = object->qualifiedName; 118
119 return;
120 }
This function returns the handle for the hierarchy of an object.
TPMI_RH_HIERARCHY
ObjectDataGetHierarchy(
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
143 }
This function returns the handle of the hierarchy to which a handle belongs. This function is similar to ObjectDataGetHierarchy() but this routine takes a handle but ObjectDataGetHierarchy() takes an pointer to an object.
This function requires that handle references a loaded object.
TPMI_RH_HIERARCHY
ObjectGetHierarchy(
TPMI_DH_OBJECT handle // IN :object handle
147 )
148 {
149 OBJECT *object = ObjectGet(handle); 150
151 return ObjectDataGetHierarchy(object);
152 }
This function is used to allocate a slot in internal object array.
Return Value | Meaning |
TRUE | allocate success |
FALSE | do not have free slot |
static BOOL
ObjectAllocateSlot(
TPMI_DH_OBJECT *handle, // OUT: handle of allocated object
OBJECT **object // OUT: points to the allocated object
157 )
158 {
159 UINT32 i; 160
// find an unoccupied handle slot
for(i = 0; i < MAX_LOADED_OBJECTS; i++)
163 {
164 if(!s_objects[i].occupied) // If found a free slot
165 {
// Mark the slot as occupied
s_objects[i].occupied = TRUE;
break;
169 }
170 }
// If we reach the end of object slot without finding a free one, return
// error.
if(i == MAX_LOADED_OBJECTS) return FALSE; 174
*handle = i + TRANSIENT_FIRST;
*object = &s_objects[i].object.entity; 177
// Initialize the object attributes
MemorySet(&((*object)->attributes), 0, sizeof(OBJECT_ATTRIBUTES)); 180
181 return TRUE;
182 }
This function loads an object into an internal object structure. If an error is returned, the internal state is unchanged.
Error Returns | Meaning |
TPM_RC_BINDING | if the public and sensitive parts of the object are not matched |
TPM_RC_KEY | if the parameters in the public area of the object are not consistent |
TPM_RC_OBJECT_MEMORY | if there is no free slot for an object |
TPM_RC_TYPE | the public and private parts are not the same type |
TPM_RC
ObjectLoad(
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy to which the object belongs
TPMT_PUBLIC *publicArea, // IN: public area
TPMT_SENSITIVE *sensitive, // IN: sensitive area (may be null)
TPM2B_NAME *name, // IN: object's name (may be null)
TPM_HANDLE parentHandle, // IN: handle of parent
BOOL skipChecks, // IN: flag to indicate if it is OK to skip
// consistency checks.
TPMI_DH_OBJECT *handle // OUT: object handle
193 )
194 {
OBJECT *object = NULL;
OBJECT *parent = NULL;
TPM_RC result = TPM_RC_SUCCESS;
TPM2B_NAME parentQN; // Parent qualified name 199
// Try to allocate a slot for new object
if(!ObjectAllocateSlot(handle, &object))
return TPM_RC_OBJECT_MEMORY; 203
// Initialize public
object->publicArea = *publicArea;
if(sensitive != NULL)
object->sensitive = *sensitive; 208
// Are the consistency checks needed
if(!skipChecks)
211 {
// Check if key size matches
if(!CryptObjectIsPublicConsistent(&object->publicArea))
214 {
result = TPM_RC_KEY;
goto ErrorExit;
217 }
218 if(sensitive != NULL)
219 {
// Check if public type matches sensitive type
result = CryptObjectPublicPrivateMatch(object);
if(result != TPM_RC_SUCCESS)
goto ErrorExit;
224 }
225 }
226 object->attributes.publicOnly = (sensitive == NULL); 227
// If 'name' is NULL, then there is nothing left to do for this
// object as it has no qualified name and it is not a member of any
// hierarchy and it is temporary
if(name == NULL || name->t.size == 0)
232 {
object->qualifiedName.t.size = 0;
object->name.t.size = 0;
object->attributes.temporary = SET;
return TPM_RC_SUCCESS;
237 }
238 // If parent handle is a permanent handle, it is a primary or temporary
239 | // object | |
240 | if(HandleGetType(parentHandle) == TPM_HT_PERMANENT) | |
241 | { | |
242 | // initialize QN | |
243 | parentQN.t.size = 4; | |
244 | ||
245 | // for a primary key, parent qualified name is the handle of | hierarchy |
246 | UINT32_TO_BYTE_ARRAY(parentHandle, parentQN.t.name); | |
247 | } | |
248 | else | |
249 | { | |
250 | // Get hierarchy and qualified name of parent | |
251 | ObjectGetQualifiedName(parentHandle, &parentQN); | |
252 | ||
253 | // Check for stClear object | |
254 | parent = ObjectGet(parentHandle); | |
255 | if( publicArea->objectAttributes.stClear == SET | |
256 | || parent->attributes.stClear == SET) | |
257 | object->attributes.stClear = SET; | |
258 | ||
259 | } | |
260 | object->name = *name; | |
261 | ||
262 | // Compute object qualified name | |
263 | ObjectComputeQualifiedName(&parentQN, publicArea->nameAlg, | |
264 | name, &object->qualifiedName); | |
265 | ||
266 | // Any object in TPM_RH_NULL hierarchy is temporary | |
267 | if(hierarchy == TPM_RH_NULL) | |
268 | { | |
269 | object->attributes.temporary = SET; | |
270 | } | |
271 | else if(parentQN.t.size == sizeof(TPM_HANDLE)) | |
272 | { | |
273 | // Otherwise, if the size of parent's qualified name is the | size of a |
274 | // handle, this object is a primary object | |
275 | object->attributes.primary = SET; | |
276 | } | |
277 | switch(hierarchy) | |
278 | { | |
279 | case TPM_RH_PLATFORM: | |
280 | object->attributes.ppsHierarchy = SET; | |
281 | break; | |
282 | case TPM_RH_OWNER: | |
283 | object->attributes.spsHierarchy = SET; | |
284 | break; | |
285 | case TPM_RH_ENDORSEMENT: | |
286 | object->attributes.epsHierarchy = SET; | |
287 | break; | |
288 | case TPM_RH_NULL: | |
289 | break; | |
290 | default: | |
291 | pAssert(FALSE); | |
292 | break; | |
293 | } | |
294 | return TPM_RC_SUCCESS; | |
295 | ||
296 | ErrorExit: | |
297 | ObjectFlush(*handle); | |
298 | return result; | |
299 | } |
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.
static BOOL
AllocateSequenceSlot(
TPM_HANDLE *newHandle, // OUT: receives the allocated handle
HASH_OBJECT **object, // OUT: receives pointer to allocated object
TPM2B_AUTH *auth // IN: the authValue for the slot
305 )
306 {
307 OBJECT *objectHash; // the hash as an object 308
if(!ObjectAllocateSlot(newHandle, &objectHash))
return FALSE; 311
312 *object = (HASH_OBJECT *)objectHash; 313
// Validate that the proper location of the hash state data relative to the
// object state data.
pAssert(&((*object)->auth) == &objectHash->publicArea.authPolicy); 317
// Set the common values that a sequence object shares with an ordinary object
// The type is TPM_ALG_NULL
(*object)->type = TPM_ALG_NULL; 321
// This has no name algorithm and the name is the Empty Buffer
(*object)->nameAlg = TPM_ALG_NULL; 324
// Clear the attributes
MemorySet(&((*object)->objectAttributes), 0, sizeof(TPMA_OBJECT)); 327
// A sequence object is considered to be in the NULL hierarchy so it should
// be marked as temporary so that it can't be persisted
(*object)->attributes.temporary = SET; 331
// A sequence object is DA exempt.
(*object)->objectAttributes.noDA = SET; 334
335 if(auth != NULL)
336 {
MemoryRemoveTrailingZeros(auth);
(*object)->auth = *auth;
339 }
else
(*object)->auth.t.size = 0;
return TRUE;
343 }
This function creates an internal HMAC sequence object.
Error Returns | Meaning |
TPM_RC_OBJECT_MEMORY | if there is no free slot for an object |
TPM_RC
ObjectCreateHMACSequence(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
347 | TPM_HANDLE | handle, | // | IN: | the handle associated | with | sequence |
348 | // | object |
349 | TPM2B_AUTH *auth, // IN: authValue | |
350 | TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle | |
351 | ) | |
352 | { | |
353 | HASH_OBJECT *hmacObject; | |
354 | OBJECT *keyObject; | |
355 | ||
356 | // Try to allocate a slot for new object | |
357 | if(!AllocateSequenceSlot(newHandle, &hmacObject, auth)) | |
358 | return TPM_RC_OBJECT_MEMORY; | |
359 | ||
360 | // Set HMAC sequence bit | |
361 | hmacObject->attributes.hmacSeq = SET; | |
362 | ||
363 | // Get pointer to the HMAC key object | |
364 | keyObject = ObjectGet(handle); | |
365 | ||
366 | CryptStartHMACSequence2B(hashAlg, &keyObject->sensitive.sensitive.bits.b, | |
367 | &hmacObject->state.hmacState); | |
368 | ||
369 | return TPM_RC_SUCCESS; | |
370 | } |
This function creates a hash sequence object.
Error Returns | Meaning |
TPM_RC_OBJECT_MEMORY | if there is no free slot for an object |
TPM_RC
ObjectCreateHashSequence(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
TPM2B_AUTH *auth, // IN: authValue
TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
376 )
377 {
378 HASH_OBJECT *hashObject; 379
// Try to allocate a slot for new object
if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
return TPM_RC_OBJECT_MEMORY; 383
// Set hash sequence bit
hashObject->attributes.hashSeq = SET; 386
// Start hash for hash sequence
CryptStartHashSequence(hashAlg, &hashObject->state.hashState[0]); 389
390 return TPM_RC_SUCCESS;
391 }
This function creates an event sequence object.
Error Returns | Meaning |
TPM_RC_OBJECT_MEMORY | if there is no free slot for an object |
TPM_RC
ObjectCreateEventSequence(
TPM2B_AUTH *auth, // IN: authValue
TPMI_DH_OBJECT *newHandle // OUT: sequence object handle
396 )
397 {
HASH_OBJECT *hashObject;
UINT32 count;
TPM_ALG_ID hash; 401
402 // Try to allocate a slot for new object
403 if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
404 return TPM_RC_OBJECT_MEMORY; 405
406 // Set the event sequence attribute
407 hashObject->attributes.eventSeq = SET; 408
409 // Initialize hash states for each implemented PCR algorithms
410 for(count = 0; (hash = CryptGetHashAlgByIndex(count)) != TPM_ALG_NULL; count++)
411 {
// If this is a _TPM_Init or _TPM_HashStart, the sequence object will
// not leave the TPM so it doesn't need the sequence handling
if(auth == NULL)
CryptStartHash(hash, &hashObject->state.hashState[count]);
else
CryptStartHashSequence(hash, &hashObject->state.hashState[count]);
418 }
419 return TPM_RC_SUCCESS;
420 }
This function is called to close out the event sequence and clean up the hash context states.
421 void
422 ObjectTerminateEvent(
423 void
424 )
425 {
426 HASH_OBJECT *hashObject;
427 int count;
428 BYTE buffer[MAX_DIGEST_SIZE];
429 hashObject = (HASH_OBJECT *)ObjectGet(g_DRTMHandle); 430
431 // Don't assume that this is a proper sequence object
432 if(hashObject->attributes.eventSeq)
433 {
434 // If it is, close any open hash contexts. This is done in case
435 // the crypto implementation has some context values that need to be
436 // cleaned up (hygiene).
437 //
438 for(count = 0; CryptGetHashAlgByIndex(count) != TPM_ALG_NULL; count++)
439 {
440 CryptCompleteHash(&hashObject->state.hashState[count], 0, buffer);
441 }
442 // Flush sequence object
443 ObjectFlush(g_DRTMHandle);
444 }
445
446 g_DRTMHandle = TPM_RH_UNASSIGNED;
447 }
This function loads an object from a saved object context.
Error Returns | Meaning |
TPM_RC_OBJECT_MEMORY | if there is no free slot for an object |
448 TPM_RC
449 ObjectContextLoad(
450 OBJECT *object, // IN: object structure from saved context
451 TPMI_DH_OBJECT *handle // OUT: object handle
452 )
453 {
454 OBJECT *newObject; 455
456 // Try to allocate a slot for new object
457 if(!ObjectAllocateSlot(handle, &newObject))
458 return TPM_RC_OBJECT_MEMORY; 459
460 // Copy input object data to internal structure
461 *newObject = *object; 462
463 return TPM_RC_SUCCESS;
464 }
This function frees an object slot.
This function requires that the object is loaded.
465 void
466 ObjectFlush(
467 TPMI_DH_OBJECT handle // IN: handle to be freed
468 )
469 {
470 UINT32 index = handle - TRANSIENT_FIRST;
471 pAssert(ObjectIsPresent(handle)); 472
473 // Mark the handle slot as unoccupied
474 s_objects[index].occupied = FALSE; 475
476 // With no attributes
477 MemorySet((BYTE*)&(s_objects[index].object.entity.attributes),
478 0, sizeof(OBJECT_ATTRIBUTES));
479 return;
480 }
This function is called to flush all the loaded transient objects associated with a hierarchy when the hierarchy is disabled.
481 void
482 ObjectFlushHierarchy(
483 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush
484 )
485 {
486 UINT16 i; 487
488 // iterate object slots
489 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
490 {
491 if(s_objects[i].occupied) // If found an occupied slot
492 {
493 switch(hierarchy)
494 {
case TPM_RH_PLATFORM:
if(s_objects[i].object.entity.attributes.ppsHierarchy == SET)
s_objects[i].occupied = FALSE;
break;
case TPM_RH_OWNER:
if(s_objects[i].object.entity.attributes.spsHierarchy == SET)
s_objects[i].occupied = FALSE;
break;
case TPM_RH_ENDORSEMENT:
if(s_objects[i].object.entity.attributes.epsHierarchy == SET)
s_objects[i].occupied = FALSE;
break;
default:
pAssert(FALSE);
break;
510 }
511 }
512 }
513
514 return; 515
516 }
This function loads a persistent object into a transient object slot.
This function requires that handle is associated with a persistent object.
Error Returns | Meaning |
TPM_RC_HANDLE | the persistent object does not exist or the associated hierarchy is disabled. |
TPM_RC_OBJECT_MEMORY | no object slot |
517 TPM_RC
518 ObjectLoadEvict(
519 TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it
520 // will be replace by the loaded object handle
521 TPM_CC commandCode // IN: the command being processed
522 )
523 {
524 TPM_RC result;
525 TPM_HANDLE evictHandle = *handle; // Save the evict handle
526 OBJECT *object; 527
528 // If this is an index that references a persistent object created by
529 // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE
530 if(*handle >= PLATFORM_PERSISTENT)
531 {
532 // belongs to platform
533 if(g_phEnable == CLEAR)
534 return TPM_RC_HANDLE;
535 }
536 // belongs to owner
537 else if(gc.shEnable == CLEAR)
538 return TPM_RC_HANDLE; 539
540 // Try to allocate a slot for an object
541 if(!ObjectAllocateSlot(handle, &object))
542 return TPM_RC_OBJECT_MEMORY; 543
544 // Copy persistent object to transient object slot. A TPM_RC_HANDLE
545 // may be returned at this point. This will mark the slot as containing
546 // a transient object so that it will be flushed at the end of the
547 // command
548 result = NvGetEvictObject(evictHandle, object); 549
550 // Bail out if this failed
551 if(result != TPM_RC_SUCCESS)
552 return result; 553
// check the object to see if it is in the endorsement hierarchy
// if it is and this is not a TPM2_EvictControl() command, indicate
// that the hierarchy is disabled.
// If the associated hierarchy is disabled, make it look like the
// handle is not defined
if( ObjectDataGetHierarchy(object) == TPM_RH_ENDORSEMENT
&& gc.ehEnable == CLEAR
&& commandCode != TPM_CC_EvictControl
562 )
563 return TPM_RC_HANDLE; 564
565 return result;
566 }
This function computes the Name of an object from its public area.
567 void
568 ObjectComputeName(
569 TPMT_PUBLIC *publicArea, // IN: public area of an object
570 TPM2B_NAME *name // OUT: name of the object
571 )
572 {
573 TPM2B_PUBLIC marshalBuffer;
574 BYTE *buffer; // auxiliary marshal buffer pointer
575 HASH_STATE hashState; // hash state 576
577 // if the nameAlg is NULL then there is no name.
578 if(publicArea->nameAlg == TPM_ALG_NULL)
579 {
580 name->t.size = 0;
581 return;
582 }
583 // Start hash stack
584 name->t.size = CryptStartHash(publicArea->nameAlg, &hashState); 585
586 // Marshal the public area into its canonical form
587 buffer = marshalBuffer.b.buffer; 588
589 marshalBuffer.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, NULL); 590
591 // Adding public area
592 CryptUpdateDigest2B(&hashState, &marshalBuffer.b); 593
594 // Complete hash leaving room for the name algorithm
595 CryptCompleteHash(&hashState, name->t.size, &name->t.name[2]); 596
597 // set the nameAlg
598 UINT16_TO_BYTE_ARRAY(publicArea->nameAlg, name->t.name);
599 | name->t.size += 2; | |
600 | return; | |
601 | } | |
This function computes the qualified name of an object. | ||
602 | void | |
603 | ObjectComputeQualifiedName( | |
604 | TPM2B_NAME *parentQN, // IN: parent's qualified name | |
605 | TPM_ALG_ID nameAlg, // IN: name hash | |
606 | TPM2B_NAME *name, // IN: name of the object | |
607 | TPM2B_NAME *qualifiedName // OUT: qualified name of the | object |
608 | ) | |
609 | { | |
610 | HASH_STATE hashState; // hash state | |
611 | ||
612 | // QN_A = hash_A (QN of parent || NAME_A) | |
613 | ||
614 | // Start hash | |
615 | qualifiedName->t.size = CryptStartHash(nameAlg, &hashState); | |
616 | ||
617 | // Add parent's qualified name | |
618 | CryptUpdateDigest2B(&hashState, &parentQN->b); | |
619 | ||
620 | // Add self name | |
621 | CryptUpdateDigest2B(&hashState, &name->b); | |
622 | ||
623 | // Complete hash leaving room for the name algorithm | |
624 | CryptCompleteHash(&hashState, qualifiedName->t.size, | |
625 | &qualifiedName->t.name[2]); | |
626 | UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name); | |
627 | qualifiedName->t.size += 2; | |
628 | return; | |
629 | } | |
This function determines if a public area has the attributes associated with a storage key. A storage key is an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
Return Value | Meaning |
TRUE | if the object is a storage key |
FALSE | if the object is not a storage key |
630 | BOOL | |
631 | ObjectDataIsStorage( | |
632 | TPMT_PUBLIC *publicArea // IN: public area of | the object |
633 | ) | |
634 | { | |
635 | if( CryptIsAsymAlgorithm(publicArea->type) | // must be asymmetric, |
636 | && publicArea->objectAttributes.restricted == SET | // restricted, |
637 | && publicArea->objectAttributes.decrypt == SET | // decryption key |
638 | && publicArea->objectAttributes.sign == CLEAR | // can not be sign key |
639 | ) | |
640 | return TRUE; | |
641 | else | |
642 | return FALSE; | |
643 | } |
This function determines if an object has the attributes associated with a storage key. A storage key is an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
Return Value | Meaning |
TRUE | if the object is a storage key |
FALSE | if the object is not a storage key |
644 BOOL
645 ObjectIsStorage(
646 TPMI_DH_OBJECT handle // IN: object handle 647 )
648 {
649 OBJECT *object = ObjectGet(handle); 650 return ObjectDataIsStorage(&object->publicArea);
651 }
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.
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
652 TPMI_YES_NO
653 ObjectCapGetLoaded(
654 TPMI_DH_OBJECT handle, // IN: start handle
655 UINT32 count, // IN: count of returned handles 656 TPML_HANDLE *handleList // OUT: list of handle
657 )
658 {
659 TPMI_YES_NO more = NO;
660 UINT32 i;
661
662 pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); 663
664 // Initialize output handle list 665 handleList->count = 0;
666
667 // The maximum count of handles we may return is MAX_CAP_HANDLES 668 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
669
670 // Iterate object slots to get loaded object handles
671 for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++)
672 {
673 if(s_objects[i].occupied == TRUE)
674 {
675 // A valid transient object can not be the copy of a persistent object 676 pAssert(s_objects[i].object.entity.attributes.evict == CLEAR);
677
678 if(handleList->count < count)
679 {
680 // If we have not filled up the return list, add this object
681 // handle to it
682 handleList->handle[handleList->count] = i + TRANSIENT_FIRST;
683 handleList->count++;
684 }
685 else
686 {
687 // If the return list is full but we still have loaded object
688 // available, report this and stop iterating
689 more = YES;
690 break;
691 }
692 }
693 }
694
695 return more;
696 }
This function returns an estimate of the number of additional transient objects that could be loaded into the TPM.
697 UINT32
698 ObjectCapGetTransientAvail(
699 void
700 )
701 {
702 UINT32 i;
703 UINT32 num = 0;
704
705 // Iterate object slot to get the number of unoccupied slots 706 for(i = 0; i < MAX_LOADED_OBJECTS; i++)
707 {
708 if(s_objects[i].occupied == FALSE) num++; 709 }
710
711 return num;
712 }
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.
Includes, Defines, and Data Definitions
#define PCR_C
#include "InternalRoutines.h"
#include <Platform.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.
static const PCR_Attributes s_initAttributes[] =
5 {
6 // PCR 0 - 15, static RTM
7 {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
8 {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
9 {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
10 {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F}, {1, 0, 0x1F},
11
12 {0, 0x0F, 0x1F}, // PCR 16, Debug
13 {0, 0x10, 0x1C}, // PCR 17, Locality 4
14 {0, 0x10, 0x1C}, // PCR 18, Locality 3
15 {0, 0x10, 0x0C}, // PCR 19, Locality 2
16 {0, 0x14, 0x0E}, // PCR 20, Locality 1
17 {0, 0x14, 0x04}, // PCR 21, Dynamic OS
18 {0, 0x14, 0x04}, // PCR 22, Dynamic OS
{0, 0x0F, 0x1F}, // PCR 23, App specific
{0, 0x0F, 0x1F} // PCR 24, testing policy 21 };
This function indicates if a PCR belongs to a group that requires an authValue 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.
Return Value | Meaning |
TRUE: | PCR belongs an auth group |
FALSE: | PCR does not belong an auth group |
BOOL
PCRBelongsAuthGroup(
TPMI_DH_PCR handle, // IN: handle of PCR
UINT32 *groupIndex // OUT: group index if PCR belongs a
// group that allows authValue. If PCR
// does not belong to an auth group,
// the value in this parameter is
// invalid
30 )
31 {
#if NUM_AUTHVALUE_PCR_GROUP > 0
// Platform specification determines to which auth group a PCR belongs (if
// any). In this implementation, we assume there is only
// one auth group which contains PCR[20-22]. If the platform specification
// requires differently, the implementation should be changed accordingly
if(handle >= 20 && handle <= 22) 38 {
*groupIndex = 0;
return TRUE; 41 }
42
#endif
return FALSE; 45 }
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.
Return Value | Meaning |
TRUE: | PCR belongs a policy group |
FALSE: | PCR does not belong a policy group |
BOOL
PCRBelongsPolicyGroup(
TPMI_DH_PCR handle, // IN: handle of PCR
UINT32 *groupIndex // OUT: group index if PCR belongs a group that
// allows policy. If PCR does not belong to
// a policy group, the value in this
// parameter is invalid
53 )
54 {
#if NUM_POLICY_PCR_GROUP > 0
// Platform specification decides if a PCR belongs to a policy group and
// belongs to which group. In this implementation, we assume there is only
// one policy group which contains PCR20-22. If the platform specification
// requires differently, the implementation should be changed accordingly
if(handle >= 20 && handle <= 22) 61 {
*groupIndex = 0;
return TRUE; 64 }
#endif
return FALSE; 67 }
This function indicates if a PCR belongs to the TCB group.
Return Value | Meaning |
TRUE: | PCR belongs to TCB group |
FALSE: | PCR does not belong to TCB group |
static BOOL
PCRBelongsTCBGroup(
TPMI_DH_PCR handle // IN: handle of PCR 71 )
72 {
#if ENABLE_PCR_NO_INCREMENT == YES
// Platform specification decides if a PCR belongs to a TCB group. In this
// implementation, we assume PCR[20-22] belong to TCB group. If the platform
// specification requires differently, the implementation should be
// changed accordingly
if(handle >= 20 && handle <= 22)
return TRUE; 80
#endif
return FALSE; 83 }
This function indicates if a policy is available for a PCR.
Return Value | Meaning |
TRUE | the PCR should be authorized by policy |
FALSE | the PCR does not allow policy |
BOOL
PCRPolicyIsAvailable(
TPMI_DH_PCR handle // IN: PCR handle 87 )
88 {
89 UINT32 groupIndex; 90
91 return PCRBelongsPolicyGroup(handle, &groupIndex); 92 }
This function is used to access the authValue of a PCR. If PCR does not belong to an authValue group, an Empty Auth will be returned.
void
PCRGetAuthValue(
TPMI_DH_PCR handle, // IN: PCR handle
TPM2B_AUTH *auth // OUT: authValue of PCR 97 )
98 {
99 UINT32 groupIndex; 100
101 if(PCRBelongsAuthGroup(handle, &groupIndex))
102 {
103 *auth = gc.pcrAuthValues.auth[groupIndex];
104 }
105 else
106 {
107 auth->t.size = 0;
108 }
109
110 return;
111 }
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.
TPMI_ALG_HASH
PCRGetAuthPolicy(
TPMI_DH_PCR handle, // IN: PCR handle
TPM2B_DIGEST *policy // OUT: policy of PCR
116 )
117 {
118 UINT32 groupIndex; 119
120 if(PCRBelongsPolicyGroup(handle, &groupIndex))
121 {
*policy = gp.pcrPolicies.policy[groupIndex];
return gp.pcrPolicies.hashAlg[groupIndex];
124 }
125 else
126 {
policy->t.size = 0;
return TPM_ALG_NULL;
129 }
130 }
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.
void
PCRSimStart(
void
134 )
135 {
UINT32 i;
for(i = 0; i < NUM_POLICY_PCR_GROUP; i++)
138 {
gp.pcrPolicies.hashAlg[i] = TPM_ALG_NULL;
gp.pcrPolicies.policy[i].t.size = 0;
141 }
142
143 for(i = 0; i < NUM_AUTHVALUE_PCR_GROUP; i++)
144 {
145 gc.pcrAuthValues.auth[i].t.size = 0;
146 }
147
// We need to give an initial configuration on allocated PCR before
// receiving any TPM2_PCR_Allocate command to change this configuration
// When the simulation environment starts, we allocate all the PCRs
for(gp.pcrAllocated.count = 0; gp.pcrAllocated.count < HASH_COUNT;
gp.pcrAllocated.count++)
153 {
154 gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].hash
155 = CryptGetHashAlgByIndex(gp.pcrAllocated.count); 156
157 gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].sizeofSelect
158 = PCR_SELECT_MAX;
for(i = 0; i < PCR_SELECT_MAX; i++)
gp.pcrAllocated.pcrSelections[gp.pcrAllocated.count].pcrSelect[i]
161 = 0xFF;
162 | } | |
163 | ||
164 | // Store the initial configuration to NV | |
165 | NvWriteReserved(NV_PCR_POLICIES, &gp.pcrPolicies); | |
166 | NvWriteReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated); | |
167 | ||
168 | return; | |
169 | } |
This function returns the address of an array of state saved PCR based on the hash algorithm.
Return Value | Meaning |
NULL | no such algorithm |
not NULL | pointer to the 0th byte of the 0th PCR |
170 | static BYTE * | ||
171 | GetSavedPcrPointer | ( | |
172 | TPM_ALG_ID | alg, | // IN: algorithm for bank |
173 | UINT32 | pcrIndex | // IN: PCR index in PCR_SAVE |
174 | ) |
175 | { |
176 | switch(alg) |
177 | { |
178 | #ifdef TPM_ALG_SHA1 |
179 | case TPM_ALG_SHA1: |
180 | return gc.pcrSave.sha1[pcrIndex]; |
181 | break; |
182 | #endif |
183 | #ifdef TPM_ALG_SHA256 |
184 | case TPM_ALG_SHA256: |
185 | return gc.pcrSave.sha256[pcrIndex]; |
186 | break; |
187 | #endif |
188 | #ifdef TPM_ALG_SHA384 |
189 | case TPM_ALG_SHA384: |
190 | return gc.pcrSave.sha384[pcrIndex]; |
191 | break; |
192 | #endif |
193 | |
194 | #ifdef TPM_ALG_SHA512 |
195 | case TPM_ALG_SHA512: |
196 | return gc.pcrSave.sha512[pcrIndex]; |
197 | break; |
198 | #endif |
199 | #ifdef TPM_ALG_SM3_256 |
200 | case TPM_ALG_SM3_256: |
201 | return gc.pcrSave.sm3_256[pcrIndex]; |
202 | break; |
203 | #endif |
204 | default: |
205 | FAIL(FATAL_ERROR_INTERNAL); |
206 | } |
207 | //return NULL; // Can't be reached |
208 | } |
This function indicates if a PCR number for the particular hash algorithm is allocated.
Return Value | Meaning |
FALSE | PCR is not allocated |
TRUE | PCR is allocated |
209 | BOOL | |
210 | PcrIsAllocated ( | |
211 | UINT32 pcr, | // IN: The number of the PCR |
212 | TPMI_ALG_HASH hashAlg | // IN: The PCR algorithm |
213 | ) | |
214 | { | |
215 | UINT32 i; | |
216 | BOOL allocated | = FALSE; |
217 | ||
218 | if(pcr < IMPLEMENTATION_PCR) | |
219 | { | |
220 |
221 for(i = 0; i < gp.pcrAllocated.count; i++)
222 {
223 if(gp.pcrAllocated.pcrSelections[i].hash == hashAlg)
224 {
225 if(((gp.pcrAllocated.pcrSelections[i].pcrSelect[pcr/8]) 226 & (1 << (pcr % 8))) != 0)
227 | allocated = TRUE; | |||
228 | else | |||
229 | allocated = FALSE; | |||
230 | break; | |||
231 | } | |||
232 | } | |||
233 | } | |||
234 | return allocated; | |||
235 | } |
This function returns the address of an array of PCR based on the hash algorithm.
Return Value | Meaning |
NULL | no such algorithm |
not NULL | pointer to the 0th byte of the 0th PCR |
static BYTE *
GetPcrPointer (
TPM_ALG_ID alg, // IN: algorithm for bank
UINT32 pcrNumber // IN: PCR number
240 )
241 {
242 static BYTE *pcr = NULL; 243
if(!PcrIsAllocated(pcrNumber, alg))
return NULL; 246
247 switch(alg)
248 {
#ifdef TPM_ALG_SHA1
case TPM_ALG_SHA1:
pcr = s_pcrs[pcrNumber].sha1Pcr;
break;
#endif
#ifdef TPM_ALG_SHA256
case TPM_ALG_SHA256:
pcr = s_pcrs[pcrNumber].sha256Pcr;
break;
#endif
#ifdef TPM_ALG_SHA384
case TPM_ALG_SHA384:
pcr = s_pcrs[pcrNumber].sha384Pcr;
break;
#endif
#ifdef TPM_ALG_SHA512
case TPM_ALG_SHA512:
pcr = s_pcrs[pcrNumber].sha512Pcr;
break;
#endif
#ifdef TPM_ALG_SM3_256
case TPM_ALG_SM3_256:
pcr = s_pcrs[pcrNumber].sm3_256Pcr;
break;
#endif
default:
pAssert(FALSE);
break;
277 }
278
279 return pcr;
280 }
This function indicates if an indicated PCR number is selected by the bit map in selection.
Return Value | Meaning |
FALSE | PCR is not selected |
TRUE | PCR is selected |
281 | static BOOL | |
282 | IsPcrSelected ( | |
283 | UINT32 pcr, // IN: The number of the PCR | |
284 | TPMS_PCR_SELECTION *selection // IN: The selection structure | |
285 | ) | |
286 | { | |
287 | BOOL selected = FALSE; | |
288 | if( pcr < IMPLEMENTATION_PCR | |
289 | && ((selection->pcrSelect[pcr/8]) & (1 << (pcr % 8))) != 0) | |
290 | selected = TRUE; | |
291 | ||
292 | return selected; | |
293 | } | |
This function modifies a PCR selection array based on the implemented PCR. | ||
294 | static void | |
295 | FilterPcr( | |
296 | TPMS_PCR_SELECTION *selection // IN: input PCR selection | |
297 | ) | |
298 | { | |
299 | UINT32 i; | |
300 | TPMS_PCR_SELECTION *allocated = NULL; | |
301 | ||
302 | // If size of select is less than PCR_SELECT_MAX, zero the unspecified | PCR |
303 | for(i = selection->sizeofSelect; i < PCR_SELECT_MAX; i++) | |
304 | selection->pcrSelect[i] = 0; | |
305 | ||
306 | // Find the internal configuration for the bank | |
307 | for(i = 0; i < gp.pcrAllocated.count; i++) | |
308 | { | |
309 | if(gp.pcrAllocated.pcrSelections[i].hash == selection->hash) | |
310 | { | |
311 | allocated = &gp.pcrAllocated.pcrSelections[i]; | |
312 | break; | |
313 | } | |
314 | } | |
315 | ||
316 | for (i = 0; i < selection->sizeofSelect; i++) | |
317 | { | |
318 | if(allocated == NULL) | |
319 | { | |
320 | // If the required bank does not exist, clear input selection | |
321 | selection->pcrSelect[i] = 0; | |
322 | } | |
323 | else | |
324 | selection->pcrSelect[i] &= allocated->pcrSelect[i]; | |
325 | } |
327 return;
328 }
This function does the DRTM and H-CRTM processing it is called from _TPM_Hash_End().
void
PcrDrtm(
const TPMI_DH_PCR pcrHandle, // IN: the index of the PCR to be
// modified
const TPMI_ALG_HASH hash, // IN: the bank identifier
const TPM2B_DIGEST *digest // IN: the digest to modify the PCR
335 )
336 {
337 BYTE *pcrData = GetPcrPointer(hash, pcrHandle); 338
339 if(pcrData != NULL)
340 {
// Rest the PCR to zeros
MemorySet(pcrData, 0, digest->t.size); 343
// if the TPM has not started, then set the PCR to 0...04 and then extend
if(!TPMIsStarted())
346 {
347 pcrData[digest->t.size - 1] = 4;
348 }
// Now, extend the value
PCRExtend(pcrHandle, hash, digest->t.size, (BYTE *)digest->t.buffer);
351 }
352 }
This function initializes the PCR subsystem at TPM2_Startup().
void
PCRStartup(
STARTUP_TYPE type, // IN: startup type
BYTE locality // IN: startup locality
357 )
358 {
UINT32 pcr, j;
UINT32 saveIndex = 0; 361
362 g_pcrReConfig = FALSE; 363
364 if(type != SU_RESUME)
365 {
// PCR generation counter is cleared at TPM_RESET and TPM_RESTART
gr.pcrCounter = 0;
368 }
369
// Initialize/Restore PCR values
for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
372 {
// On resume, need to know if this PCR had its state saved or not
UINT32 stateSaved =
(type == SU_RESUME && s_initAttributes[pcr].stateSave == SET) ? 1 : 0; 376
// If this is the H-CRTM PCR and we are not doing a resume and we
// had an H-CRTM event, then we don't change this PCR
if(pcr == HCRTM_PCR && type != SU_RESUME && g_DrtmPreStartup == TRUE)
380 | continue; | |
381 | ||
382 | // Iterate each hash algorithm bank | |
383 | for(j = 0; j < gp.pcrAllocated.count; j++) | |
384 | { | |
385 | TPMI_ALG_HASH hash = gp.pcrAllocated.pcrSelections[j].hash; | |
386 | BYTE *pcrData = GetPcrPointer(hash, pcr); | |
387 | UINT16 pcrSize = CryptGetHashDigestSize(hash); | |
388 | ||
389 | if(pcrData != NULL) | |
390 | { | |
391 | // if state was saved | |
392 | if(stateSaved == 1) | |
393 | { | |
394 | // Restore saved PCR value | |
395 | BYTE *pcrSavedData; | |
396 | pcrSavedData = GetSavedPcrPointer( | |
397 | gp.pcrAllocated.pcrSelections[j].hash, | |
398 | saveIndex); | |
399 | MemoryCopy(pcrData, pcrSavedData, pcrSize, pcrSize); | |
400 | } | |
401 | else | |
402 | // PCR was not restored by state save | |
403 | { | |
404 | // If the reset locality of the PCR is 4, then | |
405 | // the reset value is all one's, otherwise it is | |
406 | // all zero. | |
407 | if((s_initAttributes[pcr].resetLocality & 0x10) != 0) | |
408 | MemorySet(pcrData, 0xFF, pcrSize); | |
409 | else | |
410 | { | |
411 | MemorySet(pcrData, 0, pcrSize); | |
412 | if(pcr == HCRTM_PCR) | |
413 | pcrData[pcrSize-1] = locality; | |
414 | } | |
415 | } | |
416 | } | |
417 | } | |
418 | saveIndex += stateSaved; | |
419 | } | |
420 |
421 // Reset authValues
422 if(type != SU_RESUME)
423 {
424 for(j = 0; j < NUM_AUTHVALUE_PCR_GROUP; j++)
425 {
426 gc.pcrAuthValues.auth[j].t.size = 0;
427 }
428 }
429
430 }
This function is used to save the PCR values that will be restored on TPM Resume.
431 void
432 PCRStateSave(
433 TPM_SU type // IN: startup type
434 )
435 {
436 UINT32 pcr, j;
437 UINT32 saveIndex = 0;
439 | // if state save CLEAR, nothing to be done. Return here | |
440 | if(type == TPM_SU_CLEAR) return; | |
441 | ||
442 | // Copy PCR values to the structure that should be saved to NV | |
443 | for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++) | |
444 | { | |
445 | UINT32 stateSaved = (s_initAttributes[pcr].stateSave == SET) ? 1 : 0; | |
446 | ||
447 | // Iterate each hash algorithm bank | |
448 | for(j = 0; j < gp.pcrAllocated.count; j++) | |
449 | { | |
450 | BYTE *pcrData; | |
451 | UINT32 pcrSize; | |
452 | ||
453 | pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[j].hash, pcr); | |
454 | ||
455 | if(pcrData != NULL) | |
456 | { | |
457 | pcrSize | |
458 | = CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[j].hash); | |
459 | ||
460 | if(stateSaved == 1) | |
461 | { | |
462 | // Restore saved PCR value | |
463 | BYTE *pcrSavedData; | |
464 | pcrSavedData | |
465 | = GetSavedPcrPointer(gp.pcrAllocated.pcrSelections[j].hash, | |
466 | saveIndex); | |
467 | MemoryCopy(pcrSavedData, pcrData, pcrSize, pcrSize); | |
468 | } | |
469 | } | |
470 | } | |
471 | saveIndex += stateSaved; | |
472 | } | |
473 | ||
474 | return; | |
475 | } |
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.
Return Value | Meaning |
TRUE | PCR is state saved |
FALSE | PCR is not state saved |
476 | BOOL | |
477 | PCRIsStateSaved( | |
478 | TPMI_DH_PCR handle // | IN: PCR handle to be extended |
479 | ) | |
480 | { | |
481 | UINT32 pcr = handle - | PCR_FIRST; |
482 | ||
483 | if(s_initAttributes[pcr].stateSave | == SET) |
484 | return TRUE; | |
485 | else | |
486 | return FALSE; | |
487 | } |
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.
Return Value | Meaning |
TRUE | TPM2_PCR_Reset() is allowed |
FALSE | TPM2_PCR_Reset() is not allowed |
488 BOOL
489 PCRIsResetAllowed(
490 TPMI_DH_PCR handle // IN: PCR handle to be extended
491 )
492 {
493 UINT8 commandLocality;
494 UINT8 localityBits = 1;
495 UINT32 pcr = handle - PCR_FIRST; 496
497 // Check for the locality
498 commandLocality = _plat LocalityGet(); 499
500 #ifdef DRTM_PCR
501 // For a TPM that does DRTM, Reset is not allowed at locality 4
502 if(commandLocality == 4)
503 return FALSE;
504 #endif 505
506 localityBits = localityBits << commandLocality;
507 if((localityBits & s_initAttributes[pcr].resetLocality) == 0)
508 return FALSE;
509 else
510 return TRUE; 511
512 }
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.
513 void
514 PCRChanged(
515 TPM_HANDLE pcrHandle // IN: the handle of the PCR that changed.
516 )
517 {
518 // For the reference implementation, the only change that does not cause
519 // increment is a change to a PCR in the TCB group.
520 if(!PCRBelongsTCBGroup(pcrHandle))
521 gr.pcrCounter++;
522 }
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.
Return Value | Meaning |
TRUE | extend is allowed |
FALSE | extend is not allowed |
523 BOOL
524 PCRIsExtendAllowed(
525 TPMI_DH_PCR handle // IN: PCR handle to be extended
526 )
527 {
528 UINT8 commandLocality;
529 UINT8 localityBits = 1;
530 UINT32 pcr = handle - PCR_FIRST; 531
// Check for the locality
commandLocality = _plat LocalityGet();
localityBits = localityBits << commandLocality;
if((localityBits & s_initAttributes[pcr].extendLocality) == 0)
return FALSE;
else
return TRUE; 539
540 }
This function is used to extend a PCR in a specific bank.
void
PCRExtend(
TPMI_DH_PCR handle, // IN: PCR handle to be extended
TPMI_ALG_HASH hash, // IN: hash algorithm of PCR
UINT32 size, // IN: size of data to be extended
BYTE *data // IN: data to be extended
547 )
548 {
549 UINT32 pcr = handle - PCR_FIRST;
550 BYTE *pcrData;
551 HASH_STATE hashState;
552 UINT16 pcrSize; 553
554 pcrData = GetPcrPointer(hash, pcr); 555
556 // Extend PCR if it is allocated
557 if(pcrData != NULL)
558 {
559 pcrSize = CryptGetHashDigestSize(hash);
560 CryptStartHash(hash, &hashState);
561 CryptUpdateDigest(&hashState, pcrSize, pcrData);
562 CryptUpdateDigest(&hashState, size, data);
563 CryptCompleteHash(&hashState, pcrSize, pcrData); 564
565 // If PCR does not belong to TCB group, increment PCR counter
567 | ||
568 | } | |
569 | ||
570 | return; | |
571 | } |
566 if(!PCRBelongsTCBGroup(handle)) gr.pcrCounter++;
This function computes the digest of the selected PCR.
As a side-effect, selection is modified so that only the implemented PCR will have their bits still set.
void
PCRComputeCurrentDigest(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm to compute digest
TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on
// output)
TPM2B_DIGEST *digest // OUT: digest
578 )
579 {
HASH_STATE hashState;
TPMS_PCR_SELECTION *select;
BYTE *pcrData; // will point to a digest
UINT32 pcrSize;
UINT32 pcr;
UINT32 i;
586
587 // Initialize the hash
588 digest->t.size = CryptStartHash(hashAlg, &hashState);
589 pAssert(digest->t.size > 0 && digest->t.size < UINT16_MAX); 590
591 // Iterate through the list of PCR selection structures
592 for(i = 0; i < selection->count; i++)
593 {
594 // Point to the current selection
595 select = &selection->pcrSelections[i]; // Point to the current selection
596 FilterPcr(select); // Clear out the bits for unimplemented PCR 597
598 // Need the size of each digest
599 pcrSize = CryptGetHashDigestSize(selection->pcrSelections[i].hash); 600
601 // Iterate through the selection
602 for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++)
603 {
604 if(IsPcrSelected(pcr, select)) // Is this PCR selected 605 {
606 // Get pointer to the digest data for the bank
607 pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr);
608 pAssert(pcrData != NULL);
609 CryptUpdateDigest(&hashState, pcrSize, pcrData); // add to digest 610 }
611 }
612 }
613 // Complete hash stack
614 CryptCompleteHash2B(&hashState, &digest->b);
615
616 return;
617 }
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.
618 void
619 PCRRead(
620 TPML_PCR_SELECTION *selection, // IN/OUT: PCR selection (filtered on 621 // output)
622 TPML_DIGEST *digest, // OUT: digest
623 UINT32 *pcrCounter // OUT: the current value of PCR generation
624 | // number | ||
625 | ) | ||
626 | { | ||
627 | TPMS_PCR_SELECTION *select; | ||
628 | BYTE *pcrData; // will point to a digest | ||
629 | UINT32 pcr; | ||
630 | UINT32 i; | ||
631 | |||
632 | digest->count = 0; | ||
633 | |||
634 | // Iterate through the list of PCR selection structures | ||
635 | for(i = 0; i < selection->count; i++) | ||
636 | { | ||
637 | // Point to the current selection | ||
638 | select = &selection->pcrSelections[i]; // Point to the current selection | ||
639 | FilterPcr(select); // Clear out the bits for unimplemented PCR | ||
640 | |||
641 | // Iterate through the selection | ||
642 | for (pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++) | ||
643 | { | ||
644 | if(IsPcrSelected(pcr, select)) // Is this PCR selected | ||
645 | { | ||
646 | // Check if number of digest exceed upper bound | ||
647 | if(digest->count > 7) | ||
648 | { | ||
649 | // Clear rest of the current select bitmap | ||
650 | while( pcr < IMPLEMENTATION_PCR | ||
651 | // do not round up! | ||
652 | && (pcr / 8) < select->sizeofSelect) | ||
653 | { | ||
654 | // do not round up! | ||
655 | select->pcrSelect[pcr/8] &= (BYTE) ~(1 << (pcr % 8)); | ||
656 | pcr++; | ||
657 | } | ||
658 | // Exit inner loop | ||
659 | break;; | ||
660 | } | ||
661 | // Need the size of each digest | ||
662 | digest->digests[digest->count].t.size = | ||
663 | CryptGetHashDigestSize(selection->pcrSelections[i].hash); | ||
664 | |||
665 | // Get pointer to the digest data for the bank | ||
666 | pcrData = GetPcrPointer(selection->pcrSelections[i].hash, pcr); | ||
667 | pAssert(pcrData != NULL); | ||
668 | // Add to the data to digest | ||
669 | MemoryCopy(digest->digests[digest->count].t.buffer, | ||
670 | pcrData, | ||
671 | digest->digests[digest->count].t.size, | ||
672 | digest->digests[digest->count].t.size); | ||
673 | digest->count++; | ||
674 | } | ||
675 | } | ||
676 | // If we exit inner loop because we have exceed the output upper bound | ||
677 | if(digest->count > 7 && pcr < IMPLEMENTATION_PCR) | ||
678 | { | ||
679 | // Clear rest of the selection | ||
680 | while(i < selection->count) | ||
681 | { | ||
682 | MemorySet(selection->pcrSelections[i].pcrSelect, 0, | ||
683 | selection->pcrSelections[i].sizeofSelect); | ||
684 | i++; | ||
685 | } | ||
686 | // exit outer loop | ||
687 | break; | ||
688 | } | ||
689 | } |
691 *pcrCounter = gr.pcrCounter; 692
693 return;
694 }
This function is used by _TPM_Hash_End() to set a PCR to the computed hash of the H-CRTM event.
695 void
696 PcrWrite(
697 TPMI_DH_PCR handle, // IN: PCR handle to be extended 698 TPMI_ALG_HASH hash, // IN: hash algorithm of PCR
699 TPM2B_DIGEST *digest // IN: the new value 700 )
701 {
702 UINT32 pcr = handle - PCR_FIRST;
703 BYTE *pcrData;
704
705 // Copy value to the PCR if it is allocated 706 pcrData = GetPcrPointer(hash, pcr);
707 if(pcrData != NULL)
708 {
709 MemoryCopy(pcrData, digest->t.buffer, digest->t.size, digest->t.size); ; 710 }
711
712 return;
713 }
This function is used to change the PCR allocation.
Error Returns | Meaning |
TPM_RC_SUCCESS | allocate success |
TPM_RC_NO_RESULTS | allocate failed |
TPM_RC_PCR | improper allocation |
714 TPM_RC
715 PCRAllocate(
716 TPML_PCR_SELECTION *allocate, // IN: required allocation 717 UINT32 *maxPCR, // OUT: Maximum number of PCR 718 UINT32 *sizeNeeded, // OUT: required space
719 UINT32 *sizeAvailable // OUT: available space 720 )
721 {
722 UINT32 i, j, k;
723 TPML_PCR_SELECTION newAllocate;
724 // Initialize the flags to indicate if HCRTM PCR and DRTM PCR are allocated. 725 BOOL pcrHcrtm = FALSE;
726 BOOL pcrDrtm = FALSE;
727
728 // Create the expected new PCR allocation based on the existing allocation 729 // and the new input:
730 // 1. if a PCR bank does not appear in the new allocation, the existing 731 // allocation of this PCR bank will be preserved.
732 // 2. if a PCR bank appears multiple times in the new allocation, only the 733 // last one will be in effect.
734 newAllocate = gp.pcrAllocated;
735 for(i = 0; i < allocate->count; i++) 736 {
737 for(j = 0; j < newAllocate.count; j++)
738 {
739 // If hash matches, the new allocation covers the old allocation 740 // for this particular bank.
741 // The assumption is the initial PCR allocation (from manufacture) 742 // has all the supported hash algorithms with an assigned bank
743 // (possibly empty). So there must be a match for any new bank 744 // allocation from the input.
745 if(newAllocate.pcrSelections[j].hash ==
746 allocate->pcrSelections[i].hash)
747 {
748 newAllocate.pcrSelections[j] = allocate->pcrSelections[i];
749 break;
750 }
751 }
752 // The j loop must exit with a match.
753 pAssert(j < newAllocate.count); 754 }
755
756 // Max PCR in a bank is MIN(implemented PCR, PCR with attributes defined) 757 *maxPCR = sizeof(s_initAttributes) / sizeof(PCR_Attributes);
758 if(*maxPCR > IMPLEMENTATION_PCR)
759 *maxPCR = IMPLEMENTATION_PCR;
760
761 // Compute required size for allocation 762 *sizeNeeded = 0;
763 for(i = 0; i < newAllocate.count; i++) 764 {
765 UINT32 digestSize
766 = CryptGetHashDigestSize(newAllocate.pcrSelections[i].hash);
767 #if defined(DRTM_PCR)
768 // Make sure that we end up with at least one DRTM PCR 769 # define PCR_DRTM (PCR_FIRST + DRTM_PCR) // for cosmetics
770 pcrDrtm = pcrDrtm || TEST_BIT(PCR_DRTM, newAllocate.pcrSelections[i]); 771 #else // if DRTM PCR is not required, indicate that the allocation is OK
772 pcrDrtm = TRUE; 773 #endif
774
775 #if defined(HCRTM_PCR)
776 // and one HCRTM PCR (since this is usually PCR 0...) 777 # define PCR_HCRTM (PCR_FIRST + HCRTM_PCR)
778 pcrHcrtm = pcrDrtm || TEST_BIT(PCR_HCRTM, newAllocate.pcrSelections[i]); 779 #else
780 pcrHcrtm = TRUE; 781 #endif
782 for(j = 0; j < newAllocate.pcrSelections[i].sizeofSelect; j++) 783 {
784 BYTE mask = 1;
785 for(k = 0; k < 8; k++)
786 {
787 if((newAllocate.pcrSelections[i].pcrSelect[j] & mask) != 0) 788 *sizeNeeded += digestSize;
789 mask = mask << 1;
790 }
791 }
792 }
793
794 if(!pcrDrtm || !pcrHcrtm) 795 return TPM_RC_PCR;
796
797 // In this particular implementation, we always have enough space to
798 // allocate PCR. Different implementation may return a sizeAvailable less 799 // than the sizeNeed.
800 *sizeAvailable = sizeof(s_pcrs);
801
802 // Save the required allocation to NV. Note that after NV is written, the 803 // PCR allocation in NV is no longer consistent with the RAM data
804 // gp.pcrAllocated. The NV version reflect the allocate after next 805 // TPM_RESET, while the RAM version reflects the current allocation 806 NvWriteReserved(NV_PCR_ALLOCATED, &newAllocate);
807
808 return TPM_RC_SUCCESS;
809
810 }
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.
811 void
812 PCRSetValue(
813 TPM_HANDLE handle, // IN: the handle of the PCR to set 814 INT8 initialValue // IN: the value to set
815 )
816 {
817 int i;
818 UINT32 pcr = handle - PCR_FIRST; 819 TPMI_ALG_HASH hash;
820 UINT16 digestSize;
821 BYTE *pcrData;
822
823 // Iterate supported PCR bank algorithms to reset 824 for(i = 0; i < HASH_COUNT; i++)
825 {
826 hash = CryptGetHashAlgByIndex(i);
827 // Prevent runaway
828 if(hash == TPM_ALG_NULL) 829 break;
830
831 // Get a pointer to the data
832 pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr); 833
834 // If the PCR is allocated
835 if(pcrData != NULL)
836 {
837 // And the size of the digest
838 digestSize = CryptGetHashDigestSize(hash); 839
840 // Set the LSO to the input value
841 pcrData[digestSize - 1] = initialValue;
842
843 // Sign extend
844 if(initialValue >= 0)
845 MemorySet(pcrData, 0, digestSize - 1);
846 else
847 MemorySet(pcrData, -1, digestSize - 1);
848 }
849 }
850 }
This function is used to reset a dynamic PCR to 0. This function is used in DRTM sequence.
851 void
852 PCRResetDynamics(
853 | void | |
854 | ) | |
855 | { | |
856 | UINT32 pcr, i; | |
857 | ||
858 | // Initialize PCR values | |
859 | for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++) | |
860 | { | |
861 | // Iterate each hash algorithm bank | |
862 | for(i = 0; i < gp.pcrAllocated.count; i++) | |
863 | { | |
864 | BYTE *pcrData; | |
865 | UINT32 pcrSize; | |
866 | ||
867 | pcrData = GetPcrPointer(gp.pcrAllocated.pcrSelections[i].hash, pcr); | |
868 | ||
869 | if(pcrData != NULL) | |
870 | { | |
871 | pcrSize = | |
872 | CryptGetHashDigestSize(gp.pcrAllocated.pcrSelections[i].hash); | |
873 | ||
874 | // Reset PCR | |
875 | // Any PCR can be reset by locality 4 should be reset to 0 | |
876 | if((s_initAttributes[pcr].resetLocality & 0x10) != 0) | |
877 | MemorySet(pcrData, 0, pcrSize); | |
878 | } | |
879 | } | |
880 | } | |
881 | return; | |
882 | } |
This function is used to get the current allocation of PCR banks.
Return Value | Meaning |
YES: | if the return count is 0 |
NO: | if the return count is not 0 |
883 | TPMI_YES_NO | |
884 | PCRCapGetAllocation( | |
885 | UINT32 count, | // IN: count of return |
886 | TPML_PCR_SELECTION *pcrSelection | // OUT: PCR allocation list |
887 | ) | |
888 | { | |
889 | if(count == 0) | |
890 | { | |
891 | pcrSelection->count = 0; | |
892 | return YES; | |
893 | } | |
894 | else | |
895 | { | |
896 | *pcrSelection = gp.pcrAllocated; | |
897 | return NO; | |
898 | } | |
899 | } |
This function sets a bit in a bitmap array.
900 static void
901 PCRSetSelectBit(
902 UINT32 pcr, // IN: PCR number
903 BYTE *bitmap // OUT: bit map to be set 904 )
905 {
906 bitmap[pcr / 8] |= (1 << (pcr % 8));
907 return;
908 }
This function returns the selected PCR property.
Return Value | Meaning |
TRUE | the property type is implemented |
FALSE | the property type is not implemented |
909 | static BOOL | |
910 | PCRGetProperty( | |
911 | TPM_PT_PCR property, | |
912 | TPMS_TAGGED_PCR_SELECT *select | |
913 | ) | |
914 | { | |
915 | UINT32 pcr; | |
916 | UINT32 groupIndex; | |
917 | ||
918 | select->tag = property; | |
919 | // Always set the bitmap to be the size of all PCR | |
920 | select->sizeofSelect = (IMPLEMENTATION_PCR + 7) / 8; | |
921 | ||
922 | // Initialize bitmap | |
923 | MemorySet(select->pcrSelect, 0, select->sizeofSelect); | |
924 | ||
925 | // Collecting properties | |
926 | for(pcr = 0; pcr < IMPLEMENTATION_PCR; pcr++) | |
927 | { | |
928 | switch(property) | |
929 | { | |
930 | case TPM_PT_PCR_SAVE: | |
931 | if(s_initAttributes[pcr].stateSave == SET) | |
932 | PCRSetSelectBit(pcr, select->pcrSelect); | |
933 | break; | |
934 | case TPM_PT_PCR_EXTEND_L0: | |
935 | if((s_initAttributes[pcr].extendLocality & 0x01) | != 0) |
936 | PCRSetSelectBit(pcr, select->pcrSelect); | |
937 | break; | |
938 | case TPM_PT_PCR_RESET_L0: |
if((s_initAttributes[pcr].resetLocality & 0x01) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_EXTEND_L1:
if((s_initAttributes[pcr].extendLocality & 0x02) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_RESET_L1:
if((s_initAttributes[pcr].resetLocality & 0x02) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_EXTEND_L2:
if((s_initAttributes[pcr].extendLocality & 0x04) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_RESET_L2:
if((s_initAttributes[pcr].resetLocality & 0x04) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_EXTEND_L3:
if((s_initAttributes[pcr].extendLocality & 0x08) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_RESET_L3:
if((s_initAttributes[pcr].resetLocality & 0x08) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_EXTEND_L4:
if((s_initAttributes[pcr].extendLocality & 0x10) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_RESET_L4:
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
case TPM_PT_PCR_DRTM_RESET:
// DRTM reset PCRs are the PCR reset by locality 4
if((s_initAttributes[pcr].resetLocality & 0x10) != 0)
PCRSetSelectBit(pcr, select->pcrSelect);
break;
#if NUM_POLICY_PCR_GROUP > 0
case TPM_PT_PCR_POLICY:
if(PCRBelongsPolicyGroup(pcr + PCR_FIRST, &groupIndex)) 982 PCRSetSelectBit(pcr, select->pcrSelect);
983 break;
984 #endif
985 #if NUM_AUTHVALUE_PCR_GROUP > 0
986 case TPM_PT_PCR_AUTH:
987 if(PCRBelongsAuthGroup(pcr + PCR_FIRST, &groupIndex)) 988 PCRSetSelectBit(pcr, select->pcrSelect);
break;
#endif
#if ENABLE_PCR_NO_INCREMENT == YES
case TPM_PT_PCR_NO_INCREMENT:
if(PCRBelongsTCBGroup(pcr + PCR_FIRST))
PCRSetSelectBit(pcr, select->pcrSelect);
break;
#endif
default:
// If property is not supported, stop scanning PCR attributes
// and return.
1000 return FALSE;
1001 break;
1002 }
1003 }
1004 return TRUE;
1005 }
This function returns a list of PCR properties starting at property.
Return Value | Meaning |
YES: | if no more property is available |
NO: | if there are more properties not reported |
1006 | TPMI_YES_NO | ||
1007 | PCRCapGetProperties( | ||
1008 | TPM_PT_PCR property, | // | IN: the starting PCR property |
1009 | UINT32 count, | // | IN: count of returned propertie |
1010 | TPML_TAGGED_PCR_PROPERTY *select | // | OUT: PCR select |
1011 | ) | ||
1012 | { | ||
1013 | TPMI_YES_NO more = NO; | ||
1014 | UINT32 i; | ||
1015 | |||
1016 | // Initialize output property list |
1017 select->count = 0;
1018
1019 | // The maximum count of properties we may return is MAX_PCR_PROPERTIES | |
1020 | if(count > MAX_PCR_PROPERTIES) count = MAX_PCR_PROPERTIES; | |
1021 | ||
1022 | // TPM_PT_PCR_FIRST is defined as 0 in spec. It ensures that property | |
1023 | // value would never be less than TPM_PT_PCR_FIRST | |
1024 | pAssert(TPM_PT_PCR_FIRST == 0); | |
1025 | ||
1026 | // Iterate PCR properties. TPM_PT_PCR_LAST is the index of the last property | |
1027 | // implemented on the TPM. | |
1028 | for(i = property; i <= TPM_PT_PCR_LAST; i++) | |
1029 | { | |
1030 | if(select->count < count) | |
1031 | { | |
1032 | // If we have not filled up the return list, add more properties to it | |
1033 | if(PCRGetProperty(i, &select->pcrProperty[select->count])) | |
1034 | // only increment if the property is implemented | |
1035 | select->count++; | |
1036 | } | |
1037 | else | |
1038 | { | |
1039 | // If the return list is full but we still have properties | |
1040 | // available, report this and stop iterating. | |
1041 | more = YES; | |
1042 | break; | |
1043 | } | |
1044 | } | |
1045 | return more; | |
1046 | } |
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.
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
1047 | TPMI_YES_NO | ||||
1048 | PCRCapGetHandles( | ||||
1049 | TPMI_DH_PCR | handle, | // | IN: start | handle |
1050 | UINT32 | count, | // | IN: count | of returned handle |
1051 | TPML_HANDLE | *handleList | // | OUT: list | of handle |
1052 | ) | |
1053 | { | |
1054 | TPMI_YES_NO more = NO; | |
1055 | UINT32 i; | |
1056 | ||
1057 | pAssert(HandleGetType(handle) == TPM_HT_PCR); | |
1058 | ||
1059 | // Initialize output handle list | |
1060 | handleList->count = 0; | |
1061 | ||
1062 | // The maximum count of handles we may return is MAX_CAP_HANDLES | |
1063 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; | |
1064 | ||
1065 | // Iterate PCR handle range | |
1066 | for(i = handle & HR_HANDLE_MASK; i <= PCR_LAST; i++) | |
1067 | { | |
1068 | if(handleList->count < count) | |
1069 | { | |
1070 | // If we have not filled up the return list, add this PCR | |
1071 | // handle to it | |
1072 | handleList->handle[handleList->count] = i + PCR_FIRST; | |
1073 | handleList->count++; | |
1074 | } | |
1075 | else | |
1076 | { | |
1077 | // If the return list is full but we still have PCR handle | |
1078 | // available, report this and stop iterating | |
1079 | more = YES; | |
1080 | break; | |
1081 | } | |
1082 | } | |
1083 | return more; | |
1084 | } |
This file contains the functions that support the physical presence operations of the TPM.
#include "InternalRoutines.h"
PhysicalPresencePreInstall_Init()
This function is used to initialize the array of commands that 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.
void
PhysicalPresencePreInstall_Init(
void
5 )
6 {
// Clear all the PP commands
MemorySet(&gp.ppList, 0,
((TPM_CC_PP_LAST - TPM_CC_PP_FIRST + 1) + 7) / 8); 10
// TPM_CC_PP_Commands always requires PP
if(CommandIsImplemented(TPM_CC_PP_Commands))
PhysicalPresenceCommandSet(TPM_CC_PP_Commands); 14
// Write PP list to NV
NvWriteReserved(NV_PP_LIST, &gp.ppList); 17
18 return; 19 }
This function is used to indicate a command that requires PP confirmation.
void
PhysicalPresenceCommandSet(
TPM_CC commandCode // IN: command code 23 )
24 {
25 UINT32 bitPos; 26
// Assume command is implemented. It should be checked before this
// function is called
pAssert(CommandIsImplemented(commandCode)); 30
// If the command is not a PP command, ignore it
if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
return;
34
35 bitPos = commandCode - TPM_CC_PP_FIRST; 36
// Set bit
gp.ppList[bitPos/8] |= 1 << (bitPos % 8); 39
40 return; 41 }
PhysicalPresenceCommandClear()
This function is used to indicate a command that no longer requires PP confirmation.
void
PhysicalPresenceCommandClear(
TPM_CC commandCode // IN: command code 45 )
46 {
47 UINT32 bitPos; 48
// Assume command is implemented. It should be checked before this
// function is called
pAssert(CommandIsImplemented(commandCode)); 52
// If the command is not a PP command, ignore it
if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
return;
56
// if the input code is TPM_CC_PP_Commands, it can not be cleared
if(commandCode == TPM_CC_PP_Commands)
return;
60
61 bitPos = commandCode - TPM_CC_PP_FIRST;
62 | ||
63 | // Set bit | |
64 | gp.ppList[bitPos/8] |= (1 << (bitPos % 8)); | |
65 | // Flip it to off | |
66 | gp.ppList[bitPos/8] ^= (1 << (bitPos % 8)); | |
67 | ||
68 | return; | |
69 | } |
This function indicates if PP confirmation is required for a command.
Return Value | Meaning |
TRUE | if physical presence is required |
FALSE | if physical presence is not required |
BOOL
PhysicalPresenceIsRequired(
TPM_CC commandCode // IN: command code 73 )
74 {
75 UINT32 bitPos; 76
// if the input commandCode is not a PP command, return FALSE
if(commandCode < TPM_CC_PP_FIRST || commandCode > TPM_CC_PP_LAST)
return FALSE; 80
81 bitPos = commandCode - TPM_CC_PP_FIRST; 82
// Check the bit map. If the bit is SET, PP authorization is required
return ((gp.ppList[bitPos/8] & (1 << (bitPos % 8))) != 0); 85
86 }
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.
Return Value | Meaning |
YES | if there are more command codes available |
NO | all the available command codes have been returned |
TPMI_YES_NO
PhysicalPresenceCapGetCCList(
TPM_CC commandCode, // IN: start command code
UINT32 count, // IN: count of returned TPM_CC
TPML_CC *commandList // OUT: list of TPM_CC 92 )
93 {
TPMI_YES_NO more = NO;
UINT32 i; 96
// Initialize output handle list
commandList->count = 0; 99
// The maximum count of command we may return is MAX_CAP_CC
if(count > MAX_CAP_CC) count = MAX_CAP_CC;
103 | // Collect PP commands | |
104 | for(i = commandCode; i <= TPM_CC_PP_LAST; i++) | |
105 | { | |
106 | if(PhysicalPresenceIsRequired(i)) | |
107 | { | |
108 | if(commandList->count < count) | |
109 | { | |
110 | // If we have not filled up the return list, add this command | |
111 | // code to it | |
112 | commandList->commandCodes[commandList->count] = i; | |
113 | commandList->count++; | |
114 | } | |
115 | else | |
116 | { | |
117 | // If the return list is full but we still have PP command | |
118 | // available, report this and stop iterating | |
119 | more = YES; | |
120 | break; | |
121 | } | |
122 | } | |
123 | } | |
124 | return more; | |
125 | } |
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.
Includes, Defines, and Local Variables
#define SESSION_C
#include "InternalRoutines.h"
#include "Platform.h"
#include "SessionProcess_fp.h"
File Scope Function -- ContextIdSetOldest()
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 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.
static void
ContextIdSetOldest(
void
8 )
9 {
CONTEXT_SLOT lowBits;
CONTEXT_SLOT entry;
CONTEXT_SLOT smallest = ((CONTEXT_SLOT) ~0);
UINT32 i;
14
// Set oldestSaveContext to a value indicating none assigned
s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; 17
lowBits = (CONTEXT_SLOT)gr.contextCounter;
for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) 20 {
21 entry = gr.contextArray[i]; 22
// only look at entries that are saved contexts
if(entry > MAX_LOADED_SESSIONS)
25 {
// Use a less than or equal in case the oldest
// is brand new (= lowBits-1) and equal to our initial
// value for smallest.
if(((CONTEXT_SLOT) (entry - lowBits)) <= smallest)
30 {
smallest = (entry - lowBits);
s_oldestSavedSession = i; 33 }
34 }
35 }
// When we finish, either the s_oldestSavedSession still has its initial
// value, or it has the index of the oldest saved context. 38 }
Startup Function -- SessionStartup()
This function initializes the session subsystem on TPM2_Startup().
void
SessionStartup(
STARTUP_TYPE type
42 )
43 {
44 UINT32 i; 45
// Initialize session slots. At startup, all the in-memory session slots
// are cleared and marked as not occupied
for(i = 0; i < MAX_LOADED_SESSIONS; i++)
s_sessions[i].occupied = FALSE; // session slot is not occupied 50
// The free session slots the number of maximum allowed loaded sessions
s_freeSessionSlots = MAX_LOADED_SESSIONS; 53
// Initialize context ID data. On a ST_SAVE or hibernate sequence, it will
// scan the saved array of session context counts, and clear any entry that
// references a session that was in memory during the state save since that
// memory was not preserved over the ST_SAVE.
if(type == SU_RESUME || type == SU_RESTART) 59 {
// On ST_SAVE we preserve the contexts that were saved but not the ones
// in memory
for (i = 0; i < MAX_ACTIVE_SESSIONS; i++)
63 {
// If the array value is unused or references a loaded session then
// that loaded session context is lost and the array entry is
// reclaimed.
if (gr.contextArray[i] <= MAX_LOADED_SESSIONS)
gr.contextArray[i] = 0; 69 }
// Find the oldest session in context ID data and set it in
// s_oldestSavedSession
ContextIdSetOldest();
73 | } | |
74 | else | |
75 | { | |
76 | // For STARTUP_CLEAR, clear out the contextArray | |
77 | for (i = 0; i < MAX_ACTIVE_SESSIONS; i++) | |
78 | gr.contextArray[i] = 0; | |
79 | ||
80 | // reset the context counter | |
81 | gr.contextCounter = MAX_LOADED_SESSIONS + 1; | |
82 | ||
83 | // Initialize oldest saved session | |
84 | s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; | |
85 | } | |
86 | return; | |
87 | } |
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.
NOTE: A PWAP authorization does not have a session.
Return Value | Meaning |
TRUE | if session is loaded |
FALSE | if it is not loaded |
BOOL
SessionIsLoaded(
TPM_HANDLE handle // IN: session handle 91 )
92 {
pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION
|| HandleGetType(handle) == TPM_HT_HMAC_SESSION); 95
96 handle = handle & HR_HANDLE_MASK; 97
// if out of range of possible active session, or not assigned to a loaded
// session return false
if( handle >= MAX_ACTIVE_SESSIONS
|| gr.contextArray[handle] == 0
|| gr.contextArray[handle] > MAX_LOADED_SESSIONS
103 )
104 return FALSE; 105
106 return TRUE;
107 }
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.
NOTE: An password authorization does not have a session.
This function requires that the handle be a valid session handle.
Return Value | Meaning |
TRUE | if session is saved |
FALSE | if it is not saved |
BOOL
SessionIsSaved(
TPM_HANDLE handle // IN: session handle
111 )
112 {
pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION
|| HandleGetType(handle) == TPM_HT_HMAC_SESSION); 115
handle = handle & HR_HANDLE_MASK;
// if out of range of possible active session, or not assigned, or
// assigned to a loaded session, return false
if( handle >= MAX_ACTIVE_SESSIONS
|| gr.contextArray[handle] == 0
|| gr.contextArray[handle] <= MAX_LOADED_SESSIONS
122 )
123 return FALSE; 124
125 return TRUE;
126 }
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.
Return Value | Meaning |
TRUE | if PCR value is current |
FALSE | if PCR value is not current |
127 | BOOL | |
128 | SessionPCRValueIsCurrent( | |
129 | TPMI_SH_POLICY handle | // IN: session handle |
130 | ) | |
131 | { |
132 SESSION *session; 133
134 | pAssert(SessionIsLoaded(handle)); | |
135 | ||
136 | session = SessionGet(handle); | |
137 | if( session->pcrCounter != 0 | |
138 | && session->pcrCounter != gr.pcrCounter | |
139 | ) | |
140 | return FALSE; | |
141 | else | |
142 | return TRUE; | |
143 | } |
This function returns a pointer to the session object associated with a session handle. The function requires that the session is loaded.
SESSION *
SessionGet(
TPM_HANDLE handle // IN: session handle
147 )
148 {
149 CONTEXT_SLOT sessionIndex; 150
pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION
|| HandleGetType(handle) == TPM_HT_HMAC_SESSION
153 );
154
155 pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); 156
// get the contents of the session array. Because session is loaded, we
// should always get a valid sessionIndex
sessionIndex = gr.contextArray[handle & HR_HANDLE_MASK] - 1; 160
161 pAssert(sessionIndex < MAX_LOADED_SESSIONS); 162
163 return &s_sessions[sessionIndex].session;
164 }
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.
return type | TPM_RC |
TPM_RC_SUCCESS | context ID was assigned |
TPM_RC_CONTEXT_GAP | can't assign a new contextID until the oldest saved session context is recycled |
TPM_RC_SESSION_HANDLE | there is no slot available in the context array for tracking of this session context |
static TPM_RC
ContextIdSessionCreate (
TPM_HANDLE *handle, // OUT: receives the assigned handle. This will
// be an index that must be adjusted by the
// caller according to the type of the
// session created
UINT32 sessionIndex // IN: The session context array entry that will
// be occupied by the created session
173 )
174 { 175
176 pAssert(sessionIndex < MAX_LOADED_SESSIONS); 177
// check to see if creating the context is safe
// Is this going to be an assignment for the last session context
// array entry? If so, then there will be no room to recycle the
// oldest context if needed. If the gap is not at maximum, then
// it will be possible to save a context if it becomes necessary.
if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS
&& s_freeSessionSlots == 1)
185 {
186 // See if the gap is at maximum
187 | if( (CONTEXT_SLOT)gr.contextCounter | |
188 | == gr.contextArray[s_oldestSavedSession]) | |
189 | ||
190 | // Note: if this is being used on a TPM.combined, this return | |
191 | // code should be transformed to an appropriate 1.2 error | |
192 | // code for this case. | |
193 | return TPM_RC_CONTEXT_GAP; | |
194 | } | |
195 | ||
196 | // Find an unoccupied entry in the contextArray | |
197 | for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++) | |
198 | { | |
199 | if(gr.contextArray[*handle] == 0) | |
200 | { | |
201 | // indicate that the session associated with this handle | |
202 | // references a loaded session | |
203 | gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex+1); | |
204 | return TPM_RC_SUCCESS; | |
205 | } | |
206 | } | |
207 | return TPM_RC_SESSION_HANDLES; | |
208 | } |
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.
Error Returns | Meaning |
TPM_RC_CONTEXT_GAP | need to recycle sessions |
TPM_RC_SESSION_HANDLE | active session space is full |
TPM_RC_SESSION_MEMORY | loaded session space is full |
TPM_RC
SessionCreate(
TPM_SE sessionType, // IN: the session type
TPMI_ALG_HASH authHash, // IN: the hash algorithm
TPM2B_NONCE *nonceCaller, // IN: initial nonceCaller
TPMT_SYM_DEF *symmetric, // IN: the symmetric algorithm
TPMI_DH_ENTITY bind, // IN: the bind object
TPM2B_DATA *seed, // IN: seed data
TPM_HANDLE *sessionHandle // OUT: the session handle
218 )
219 {
TPM_RC result = TPM_RC_SUCCESS;
CONTEXT_SLOT slotIndex;
SESSION *session = NULL; 223
pAssert( sessionType == TPM_SE_HMAC
|| sessionType == TPM_SE_POLICY
|| sessionType == TPM_SE_TRIAL); 227
// If there are no open spots in the session array, then no point in searching
if(s_freeSessionSlots == 0)
return TPM_RC_SESSION_MEMORY; 231
// Find a space for loading a session
for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
234 {
// Is this available?
if(s_sessions[slotIndex].occupied == FALSE)
237 {
session = &s_sessions[slotIndex].session;
break;
240 }
241 }
// if no spot found, then this is an internal error
pAssert (slotIndex < MAX_LOADED_SESSIONS); 244
// Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be
// returned from ContextIdHandelAssign()
result = ContextIdSessionCreate(sessionHandle, slotIndex);
if(result != TPM_RC_SUCCESS)
return result; 250
251 //*** Only return from this point on is TPM_RC_SUCCESS 252
// Can now indicate that the session array entry is occupied.
s_freeSessionSlots--;
s_sessions[slotIndex].occupied = TRUE; 256
// Initialize the session data
MemorySet(session, 0, sizeof(SESSION)); 259
// Initialize internal session data
session->authHashAlg = authHash;
// Initialize session type
if(sessionType == TPM_SE_HMAC)
264 {
265 *sessionHandle += HMAC_SESSION_FIRST; 266
267 }
268 else
269 {
270 *sessionHandle += POLICY_SESSION_FIRST; 271
// For TPM_SE_POLICY or TPM_SE_TRIAL
session->attributes.isPolicy = SET;
if(sessionType == TPM_SE_TRIAL)
session->attributes.isTrialPolicy = SET; 276
// Initialize policy session data
SessionInitPolicyData(session);
279 }
// Create initial session nonce
session->nonceTPM.t.size = nonceCaller->t.size;
CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer); 283
// Set up session parameter encryption algorithm
session->symmetric = *symmetric; 286
// If there is a bind object or a session secret, then need to compute
// a sessionKey.
if(bind != TPM_RH_NULL || seed->t.size != 0)
290 {
// sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM,
// nonceCaller, bits)
// The HMAC key for generating the sessionSecret can be the concatenation
// of an authorization value and a seed value
TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer)));
TPM2B_KEY key; 297
UINT16 hashSize; // The size of the hash used by the
// session crated by this command
TPM2B_AUTH entityAuth; // The authValue of the entity
// associated with HMAC session
302
// Get hash size, which is also the length of sessionKey
hashSize = CryptGetHashDigestSize(session->authHashAlg); 305
// Get authValue of associated entity
entityAuth.t.size = EntityGetAuthValue(bind, &entityAuth.t.buffer); 308
// Concatenate authValue and seed
pAssert(entityAuth.t.size + seed->t.size <= sizeof(key.t.buffer));
MemoryCopy2B(&key.b, &entityAuth.b, sizeof(key.t.buffer));
MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer)); 313
314 session->sessionKey.t.size = hashSize; 315
// Compute the session key
KDFa(session->authHashAlg, &key.b, "ATH", &session->nonceTPM.b,
&nonceCaller->b, hashSize * 8, session->sessionKey.t.buffer, NULL);
319 }
320
// Copy the name of the entity that the HMAC session is bound to
// Policy session is not bound to an entity
if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC)
324 {
session->attributes.isBound = SET;
SessionComputeBoundEntity(bind, &session->u1.boundEntity);
327 }
// If there is a bind object and it is subject to DA, then use of this session
// is subject to DA regardless of how it is used.
session->attributes.isDaBound = (bind != TPM_RH_NULL)
&& (IsDAExempted(bind) == FALSE);
332
// If the session is bound, then check to see if it is bound to lockoutAuth
session->attributes.isLockoutBound = (session->attributes.isDaBound == SET)
&& (bind == TPM_RH_LOCKOUT);
return TPM_RC_SUCCESS; 337
338 }
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.
Error Returns | Meaning |
TPM_RC_CONTEXT_GAP | a contextID could not be assigned. |
TPM_RC_TOO_MANY_CONTEXTS | the counter maxed out |
339 | TPM_RC | |||
340 | SessionContextSave | ( | ||
341 | TPM_HANDLE | handle, | // IN: session handle | |
342 | CONTEXT_COUNTER | *contextID | // OUT: assigned contextID | |
343 | ) | |||
344 | { | |||
345 | UINT32 | contextIndex; | ||
346 | CONTEXT_SLOT | slotIndex; | ||
347 |
348 pAssert(SessionIsLoaded(handle));
349 | ||
350 | // check to see if the gap is already maxed out | |
351 | // Need to have a saved session | |
352 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS | |
353 | // if the oldest saved session has the same value as the low bits | |
354 | // of the contextCounter, then the GAP is maxed out. | |
355 | && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter) | |
356 | return TPM_RC_CONTEXT_GAP; | |
357 | ||
358 | // if the caller wants the context counter, set it | |
359 | if(contextID != NULL) | |
360 | *contextID = gr.contextCounter; | |
361 | ||
362 | pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); | |
363 | ||
364 | contextIndex = handle & HR_HANDLE_MASK; | |
365 | ||
366 | // Extract the session slot number referenced by the contextArray | |
367 | // because we are going to overwrite this with the low order | |
368 | // contextID value. | |
369 | slotIndex = gr.contextArray[contextIndex] - 1; | |
370 | ||
371 | // Set the contextID for the contextArray | |
372 | gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter; | |
373 | ||
374 | // Increment the counter | |
375 | gr.contextCounter++; | |
376 | ||
377 | // In the unlikely event that the 64-bit context counter rolls over... | |
378 | if(gr.contextCounter == 0) | |
379 | { | |
380 | // back it up | |
381 | gr.contextCounter--; | |
382 | // return an error | |
383 | return TPM_RC_TOO_MANY_CONTEXTS; | |
384 | } | |
385 | // if the low-order bits wrapped, need to advance the value to skip over | |
386 | // the values used to indicate that a session is loaded | |
387 | if(((CONTEXT_SLOT)gr.contextCounter) == 0) | |
388 | gr.contextCounter += MAX_LOADED_SESSIONS + 1; | |
389 | ||
390 | // If no other sessions are saved, this is now the oldest. | |
391 | if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS) | |
392 | s_oldestSavedSession = contextIndex; | |
393 | ||
394 | // Mark the session slot as unoccupied | |
395 | s_sessions[slotIndex].occupied = FALSE; | |
396 | ||
397 | // and indicate that there is an additional open slot | |
398 | s_freeSessionSlots++; | |
399 | ||
400 | return TPM_RC_SUCCESS; | |
401 | } |
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.
Error Returns | Meaning |
TPM_RC_SESSION_MEMORY | no free session slots |
TPM_RC_CONTEXT_GAP | the gap count is maximum and this is not the oldest saved context |
402 TPM_RC
403 SessionContextLoad(
404 SESSION *session, // IN: session structure from saved context
405 TPM_HANDLE *handle // IN/OUT: session handle
406 )
407 {
408 UINT32 contextIndex;
409 CONTEXT_SLOT slotIndex; 410
411 pAssert( HandleGetType(*handle) == TPM_HT_POLICY_SESSION
412 || HandleGetType(*handle) == TPM_HT_HMAC_SESSION); 413
414 // Don't bother looking if no openings
415 if(s_freeSessionSlots == 0)
416 return TPM_RC_SESSION_MEMORY; 417
418 // Find a free session slot to load the session
419 for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++)
420 if(s_sessions[slotIndex].occupied == FALSE) break; 421
422 // if no spot found, then this is an internal error
423 pAssert (slotIndex < MAX_LOADED_SESSIONS); 424
425 contextIndex = *handle & HR_HANDLE_MASK; // extract the index 426
// If there is only one slot left, and the gap is at maximum, the only session
// context that we can safely load is the oldest one.
if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS
&& s_freeSessionSlots == 1
&& (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession]
&& contextIndex != s_oldestSavedSession
433 )
434 return TPM_RC_CONTEXT_GAP; 435
436 pAssert(contextIndex < MAX_ACTIVE_SESSIONS); 437
438 // set the contextArray value to point to the session slot where
439 // the context is loaded
440 gr.contextArray[contextIndex] = slotIndex + 1; 441
442 // if this was the oldest context, find the new oldest
443 if(contextIndex == s_oldestSavedSession)
444 ContextIdSetOldest(); 445
446 // Copy session data to session slot
447 s_sessions[slotIndex].session = *session; 448
449 // Set session slot as occupied
450 s_sessions[slotIndex].occupied = TRUE; 451
452 // Reduce the number of open spots
453 s_freeSessionSlots--; 454
455 return TPM_RC_SUCCESS;
456 }
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.
457 void
458 SessionFlush(
459 TPM_HANDLE handle // IN: loaded or saved session handle
460 )
461 {
462 CONTEXT_SLOT slotIndex;
463 UINT32 contextIndex; // Index into contextArray 464
465 pAssert( ( HandleGetType(handle) == TPM_HT_POLICY_SESSION
466 || HandleGetType(handle) == TPM_HT_HMAC_SESSION
467 )
468 && (SessionIsLoaded(handle) || SessionIsSaved(handle))
469 );
470
471 // Flush context ID of this session
472 // Convert handle to an index into the contextArray
473 contextIndex = handle & HR_HANDLE_MASK; 474
475 pAssert(contextIndex < sizeof(gr.contextArray)/sizeof(gr.contextArray[0])); 476
477 // Get the current contents of the array
478 slotIndex = gr.contextArray[contextIndex]; 479
480 // Mark context array entry as available
481 gr.contextArray[contextIndex] = 0; 482
483 // Is this a saved session being flushed
484 if(slotIndex > MAX_LOADED_SESSIONS)
485 {
486 // Flushing the oldest session?
487 if(contextIndex == s_oldestSavedSession)
488 // If so, find a new value for oldest.
489 ContextIdSetOldest();
490 }
491 else
492 {
493 // Adjust slot index to point to session array index
494 slotIndex -= 1; 495
496 // Free session array index
497 s_sessions[slotIndex].occupied = FALSE;
498 s_freeSessionSlots++;
499 }
500
501 return;
502 }
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.
503 void
504 SessionComputeBoundEntity(
505 | TPMI_DH_ENTITY entityHandle, // IN: handle of entity | |
506 | TPM2B_NAME *bind // OUT: binding value | |
507 | ) | |
508 | { | |
509 | TPM2B_AUTH auth; | |
510 | INT16 overlap; | |
511 | ||
512 | // Get name | |
513 | bind->t.size = EntityGetName(entityHandle, &bind->t.name); | |
514 | ||
515 | // | // The bound value of a reserved handle is the handle itself |
516 | // | if(bind->t.size == sizeof(TPM_HANDLE)) return; |
517 | ||
518 | // For all the other entities, concatenate the auth value to the name. | |
519 | // Get a local copy of the auth value because some overlapping | |
520 | // may be necessary. | |
521 | auth.t.size = EntityGetAuthValue(entityHandle, &auth.t.buffer); | |
522 | pAssert(auth.t.size <= sizeof(TPMU_HA)); | |
523 | ||
524 | // Figure out if there will be any overlap | |
525 | overlap = bind->t.size + auth.t.size - sizeof(bind->t.name); | |
526 | ||
527 | // There is overlap if the combined sizes are greater than will fit | |
528 | if(overlap > 0) | |
529 | { | |
530 | // The overlap area is at the end of the Name | |
531 | BYTE *result = &bind->t.name[bind->t.size - overlap]; | |
532 | int i; | |
533 | ||
534 | // XOR the auth value into the Name for the overlap area | |
535 | for(i = 0; i < overlap; i++) | |
536 | result[i] ^= auth.t.buffer[i]; | |
537 | } | |
538 | else | |
539 | { | |
540 | // There is no overlap | |
541 | overlap = 0; | |
542 | } | |
543 | //copy the remainder of the authData to the end of the name | |
544 | MemoryCopy(&bind->t.name[bind->t.size], &auth.t.buffer[overlap], | |
545 | auth.t.size - overlap, sizeof(bind->t.name) - bind->t.size); | |
546 | ||
547 | // Increase the size of the bind data by the size of the auth - the overlap | |
548 | bind->t.size += auth.t.size-overlap; | |
549 | ||
550 | return; | |
551 | } |
This function initializes the portions of the session policy data that are not set by the allocation of a session.
552 void
553 SessionInitPolicyData(
554 SESSION *session // IN: session handle
555 )
556 {
557 // Initialize start time
558 session->startTime = go.clock; 559
560 // Initialize policyDigest. policyDigest is initialized with a string of 0 of
561 // session algorithm digest size. Since the policy already contains all zeros
562 // it is only necessary to set the size
563 session->u2.policyDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
564 return;
565 }
This function is used to reset the policy data without changing the nonce or the start time of the session.
566 void
567 SessionResetPolicyData(
568 SESSION *session // IN: the session to reset
569 )
570 {
571 session->commandCode = 0; // No command 572
573 // No locality selected
574 MemorySet(&session->commandLocality, 0, sizeof(session->commandLocality)); 575
576 // The cpHash size to zero
577 session->u1.cpHash.b.size = 0; 578
579 // No timeout
580 session->timeOut = 0; 581
582 // Reset the pcrCounter
583 session->pcrCounter = 0; 584
585 // Reset the policy hash
586 MemorySet(&session->u2.policyDigest.t.buffer, 0,
587 session->u2.policyDigest.t.size); 588
589 // Reset the session attributes
590 MemorySet(&session->attributes, 0, sizeof(SESSION_ATTRIBUTES)); 591
592 // set the policy attribute
593 session->attributes.isPolicy = SET;
594 }
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.
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
595 | TPMI_YES_NO | |||
596 | SessionCapGetLoaded( | |||
597 | TPMI_SH_POLICY handle, | // | IN: start | handle |
598 | UINT32 count, | // | IN: count | of returned handle |
599 | TPML_HANDLE *handleList | // | OUT: list | of handle |
600 | ) | |||
601 | { | |||
602 | TPMI_YES_NO more = NO; | |||
603 | UINT32 i; | |||
604 |
605 pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION); 606
607 // Initialize output handle list
608 | handleList->count = 0; | |
609 | ||
610 | // The maximum count of handles we may return is MAX_CAP_HANDLES | |
611 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; | |
612 | ||
613 | // Iterate session context ID slots to get loaded session handles | |
614 | for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++) | |
615 | { | |
616 | // If session is active | |
617 | if(gr.contextArray[i] != 0) | |
618 | { | |
619 | // If session is loaded | |
620 | if (gr.contextArray[i] <= MAX_LOADED_SESSIONS) | |
621 | { | |
622 | if(handleList->count < count) | |
623 | { | |
624 | SESSION *session; | |
625 | ||
626 | // If we have not filled up the return list, add this | |
627 | // session handle to it | |
628 | // assume that this is going to be an HMAC session | |
629 | handle = i + HMAC_SESSION_FIRST; | |
630 | session = SessionGet(handle); | |
631 | if(session->attributes.isPolicy) | |
632 | handle = i + POLICY_SESSION_FIRST; | |
633 | handleList->handle[handleList->count] = handle; | |
634 | handleList->count++; | |
635 | } | |
636 | else | |
637 | { | |
638 | // If the return list is full but we still have loaded | object |
639 | // available, report this and stop iterating | |
640 | more = YES; | |
641 | break; | |
642 | } | |
643 | } | |
644 | } | |
645 | } | |
646 | ||
647 | return more; | |
648 | ||
649 | } |
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
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
650 TPMI_YES_NO
651 SessionCapGetSaved(
652 TPMI_SH_HMAC handle, // IN: start handle
653 UINT32 count, // IN: count of returned handle 654 TPML_HANDLE *handleList // OUT: list of handle
655 )
656 {
657 TPMI_YES_NO more = NO;
658 UINT32 i;
659
660 pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION); 661
662 // Initialize output handle list 663 handleList->count = 0;
664
665 // The maximum count of handles we may return is MAX_CAP_HANDLES 666 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
667
668 // Iterate session context ID slots to get loaded session handles 669 for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++)
670 {
671 // If session is active
672 if(gr.contextArray[i] != 0)
673 {
674 // If session is saved
675 if (gr.contextArray[i] > MAX_LOADED_SESSIONS)
676 {
677 if(handleList->count < count)
678 {
679 // If we have not filled up the return list, add this
680 // session handle to it
681 handleList->handle[handleList->count] = i + HMAC_SESSION_FIRST;
682 handleList->count++;
683 }
684 else
685 {
686 // If the return list is full but we still have loaded object
687 // available, report this and stop iterating
688 more = YES;
689 break;
690 }
691 }
692 }
693 }
694
695 return more;
696
697 }
This function return the number of authorization sessions currently loaded into TPM RAM.
698 UINT32
699 SessionCapGetLoadedNumber(
700 void
701 )
702 {
703 return MAX_LOADED_SESSIONS - s_freeSessionSlots; 704 }
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.
705 UINT32
706 SessionCapGetLoadedAvail(
707 void
708 )
709 {
710 return s_freeSessionSlots;
711 }
This function returns the number of active authorization sessions currently being tracked by the TPM.
712 UINT32
713 SessionCapGetActiveNumber(
714 void
715 )
716 {
717 UINT32 i;
718 UINT32 num = 0;
719
720 // Iterate the context array to find the number of non-zero slots 721 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
722 {
723 if(gr.contextArray[i] != 0) num++;
724 }
725
726 return num;
727 }
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.
728 UINT32
729 SessionCapGetActiveAvail(
730 void
731 )
732 {
733 UINT32 i;
734 UINT32 num = 0;
735
736 // Iterate the context array to find the number of zero slots 737 for(i = 0; i < MAX_ACTIVE_SESSIONS; i++)
738 {
739 if(gr.contextArray[i] == 0) num++;
740 | } | |
741 | ||
742 | return num; | |
743 | } |
This file contains the functions relating to the TPM's time functions including the interface to the implementation-specific time functions.
#include "InternalRoutines.h"
#include "Platform.h"
This function initialize time info at _TPM_Init().
void
TimePowerOn(
void
6 )
7 {
8 TPM_SU orderlyShutDown; 9
// Read orderly data info from NV memory
NvReadReserved(NV_ORDERLY_DATA, &go); 12
// Read orderly shut down state flag
NvReadReserved(NV_ORDERLY, &orderlyShutDown); 15
// If the previous cycle is orderly shut down, the value of the safe bit
// the same as previously saved. Otherwise, it is not safe.
if(orderlyShutDown == SHUTDOWN_NONE)
go.clockSafe= NO;
else
go.clockSafe = YES; 22
// Set the initial state of the DRBG
CryptDrbgGetPutState(PUT_STATE); 25
// Clear time since TPM power on
g_time = 0; 28
29 return; 30 }
This function updates the resetCount and restartCount components of TPMS_CLOCK_INFO structure at TPM2_Startup().
void
TimeStartup(
STARTUP_TYPE type // IN: start up type 34 )
35 {
36 if(type == SU_RESUME)
37 {
// Resume sequence
gr.restartCount++; 40 }
41 else
42 {
43 if(type == SU_RESTART)
44 {
// Hibernate sequence
gr.clearCount++;
gr.restartCount++; 48 }
49 else
50 {
// Reset sequence
// Increase resetCount
gp.resetCount++;
54
// Write resetCount to NV
NvWriteReserved(NV_RESET_COUNT, &gp.resetCount);
gp.totalResetCount++; 58
// We do not expect the total reset counter overflow during the life
// time of TPM. if it ever happens, TPM will be put to failure mode
// and there is no way to recover it.
// The reason that there is no recovery is that we don't increment
// the NV totalResetCount when incrementing would make it 0. When the
// TPM starts up again, the old value of totalResetCount will be read
// and we will get right back to here with the increment failing.
if(gp.totalResetCount == 0)
FAIL(FATAL_ERROR_INTERNAL); 68
// Write total reset counter to NV
NvWriteReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount); 71
// Reset restartCount
gr.restartCount = 0; 74 }
75 }
76
77 return; 78 }
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 implementations does not do rate limiting. If the implementation does do rate limiting, then the Clock
update should not be inhibited even when doing rather limiting.
void
TimeUpdateToCurrent(
void
82 )
83 {
UINT64 oldClock;
UINT64 elapsed;
#define CLOCK_UPDATE_MASK ((1ULL << NV_CLOCK_UPDATE_INTERVAL)- 1) 87
// Can't update time during the dark interval or when rate limiting.
if(NvIsAvailable() != TPM_RC_SUCCESS)
return;
91
// Save the old clock value
oldClock = go.clock; 94
// Update the time info to current
elapsed = _plat ClockTimeElapsed();
go.clock += elapsed;
g_time += elapsed; 99
// Check to see if the update has caused a need for an nvClock update
// CLOCK_UPDATE_MASK is measured by second, while the value in go.clock is
// recorded by millisecond. Align the clock value to second before the bit
// operations
if( ((go.clock/1000) | CLOCK_UPDATE_MASK)
> ((oldClock/1000) | CLOCK_UPDATE_MASK))
106 {
// Going to update the time state so the safe flag
// should be set
go.clockSafe = YES; 110
// Get the DRBG state before updating orderly data
CryptDrbgGetPutState(GET_STATE); 113
114 NvWriteReserved(NV_ORDERLY_DATA, &go);
115 }
116
// Call self healing logic for dictionary attack parameters
DASelfHeal(); 119
120 return;
121 }
This function is used to perform rate adjustment on Time and Clock.
void
TimeSetAdjustRate(
TPM_CLOCK_ADJUST adjust // IN: adjust constant
125 )
126 {
127 switch(adjust)
128 {
case TPM_CLOCK_COARSE_SLOWER:
_plat ClockAdjustRate(CLOCK_ADJUST_COARSE);
break;
case TPM_CLOCK_COARSE_FASTER:
_plat ClockAdjustRate(-CLOCK_ADJUST_COARSE);
break;
case TPM_CLOCK_MEDIUM_SLOWER:
_plat ClockAdjustRate(CLOCK_ADJUST_MEDIUM);
break;
case TPM_CLOCK_MEDIUM_FASTER:
_plat ClockAdjustRate(-CLOCK_ADJUST_MEDIUM);
break;
case TPM_CLOCK_FINE_SLOWER:
_plat ClockAdjustRate(CLOCK_ADJUST_FINE);
break;
case TPM_CLOCK_FINE_FASTER:
_plat ClockAdjustRate(-CLOCK_ADJUST_FINE);
break;
case TPM_CLOCK_NO_CHANGE:
break;
default:
pAssert(FALSE);
break;
152 }
153
154 return;
155 }
This function is used to access TPMS_TIME_INFO. The TPMS_TIME_INFO structure is treaded as an array of bytes, and a byte offset and length determine what bytes are returned.
Error Returns | Meaning |
TPM_RC_RANGE | invalid data range |
156 | TPM_RC | |
157 | TimeGetRange( | |
158 | UINT16 offset, // IN: offset in TPMS_TIME_INFO | |
159 | UINT16 size, // IN: size of data | |
160 | TIME_INFO *dataBuffer // OUT: result buffer | |
161 | ) | |
162 | { | |
163 | TPMS_TIME_INFO timeInfo; | |
164 | UINT16 infoSize; | |
165 | BYTE infoData[sizeof(TPMS_TIME_INFO)]; | |
166 | BYTE *buffer; | |
167 | ||
168 | // Fill TPMS_TIME_INFO structure | |
169 | timeInfo.time = g_time; | |
170 | TimeFillInfo(&timeInfo.clockInfo); | |
171 | ||
172 | // Marshal TPMS_TIME_INFO to canonical form | |
173 | buffer = infoData; | |
174 | infoSize = TPMS_TIME_INFO_Marshal(&timeInfo, &buffer, NULL); | |
175 | ||
176 | // Check if the input range is valid | |
177 | if(offset + size > infoSize) return TPM_RC_RANGE; | |
178 | ||
179 | // Copy info data to output buffer | |
180 | MemoryCopy(dataBuffer, infoData + offset, size, sizeof(TIME_INFO)); | |
181 | ||
182 | return TPM_RC_SUCCESS; | |
183 | } | |
This function gathers information to fill in a TPMS_CLOCK_INFO structure. | ||
184 | void | |
185 | TimeFillInfo( | |
186 | TPMS_CLOCK_INFO *clockInfo | |
187 | ) | |
188 | { | |
189 | clockInfo->clock = go.clock; | |
190 | clockInfo->resetCount = gp.resetCount; | |
191 | clockInfo->restartCount = gr.restartCount; | |
192 | ||
193 | // If NV is not available, clock stopped advancing and the value reported | is |
194 | // not "safe". | |
195 | if(NvIsAvailable() == TPM_RC_SUCCESS) | |
196 | clockInfo->safe = go.clockSafe; | |
197 | else | |
198 | clockInfo->safe = NO; | |
199 | ||
200 | return; | |
201 | } |
This file contains the algorithm property definitions for the algorithms and the code for the TPM2_GetCapability() to return the algorithm properties.
1 | #include "InternalRoutines.h" | |||||
2 | typedef struct | |||||
3 | { | |||||
4 | TPM_ALG_ID algID; | |||||
5 | TPMA_ALGORITHM attributes; | |||||
6 | } ALGORITHM; | |||||
7 | static const ALGORITHM s_algorithms[] | = | ||||
8 | { | |||||
9 | #ifdef TPM_ALG_RSA | |||||
10 | {TPM_ALG_RSA, {1, 0, 0, 1, | 0, | 0, | 0, | 0, | 0}}, |
11 | #endif | |||||
12 | #ifdef TPM_ALG_DES | |||||
13 | {TPM_ALG_DES, {0, 1, 0, 0, | 0, | 0, | 0, | 0, | 0}}, |
14 | #endif | |||||
15 | #ifdef TPM_ALG_3DES | |||||
16 | {TPM_ALG 3DES, {0, 1, 0, 0, | 0, | 0, | 0, | 0, | 0}}, |
17 | #endif | |||||
18 | #ifdef TPM_ALG_SHA1 | |||||
19 | {TPM_ALG_SHA1, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
20 | #endif | |||||
21 | #ifdef TPM_ALG_HMAC | |||||
22 | {TPM_ALG_HMAC, {0, 0, 1, 0, | 0, | 1, | 0, | 0, | 0}}, |
23 | #endif | |||||
24 | #ifdef TPM_ALG_AES | |||||
25 | {TPM_ALG_AES, {0, 1, 0, 0, | 0, | 0, | 0, | 0, | 0}}, |
26 | #endif | |||||
27 | #ifdef TPM_ALG_MGF1 | |||||
28 | {TPM_ALG_MGF1, {0, 0, 1, 0, | 0, | 0, | 0, | 1, | 0}}, |
29 | #endif | |||||
30 | ||||||
31 | {TPM_ALG_KEYEDHASH, {0, 0, 1, 1, | 0, | 1, | 1, | 0, | 0}}, |
32 | ||||||
33 | #ifdef TPM_ALG_XOR | |||||
34 | {TPM_ALG_XOR, {0, 1, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
35 | #endif | |||||
36 | ||||||
37 | #ifdef TPM_ALG_SHA256 | |||||
38 | {TPM_ALG_SHA256, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
39 | #endif | |||||
40 | #ifdef TPM_ALG_SHA384 | |||||
41 | {TPM_ALG_SHA384, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
42 | #endif | |||||
43 | #ifdef TPM_ALG_SHA512 | |||||
44 | {TPM_ALG_SHA512, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
45 | #endif | |||||
46 | #ifdef TPM_ALG_WHIRLPOOL512 | |||||
47 | {TPM_ALG_WHIRLPOOL512, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
48 | #endif | |||||
49 | #ifdef TPM_ALG_SM3_256 | |||||
50 | {TPM_ALG_SM3_256, {0, 0, 1, 0, | 0, | 0, | 0, | 0, | 0}}, |
51 | #endif |
79 | #ifdef TPM_ALG_KDF1_SP800_56a | ||||||||
80 | {TPM_ALG_KDF1_SP800_56a,{0, | 0, | 1, | 0, | 0, | 0, | 0, | 1, | 0}}, |
81 | #endif | ||||||||
82 | #ifdef TPM_ALG_KDF2 | ||||||||
83 | {TPM_ALG_KDF2, {0, | 0, | 1, | 0, | 0, | 0, | 0, | 1, | 0}}, |
84 | #endif | ||||||||
85 | #ifdef TPM_ALG_KDF1_SP800_108 | ||||||||
86 | {TPM_ALG_KDF1_SP800_108,{0, | 0, | 1, | 0, | 0, | 0, | 0, | 1, | 0}}, |
87 | #endif | ||||||||
88 | #ifdef TPM_ALG_ECC | ||||||||
89 | {TPM_ALG_ECC, {1, | 0, | 0, | 1, | 0, | 0, | 0, | 0, | 0}}, |
90 | #endif | ||||||||
91 | |||||||||
92 | {TPM_ALG_SYMCIPHER, {0, | 0, | 0, | 1, | 0, | 0, | 0, | 0, | 0}}, |
93 | |||||||||
94 | #ifdef TPM_ALG_CTR | ||||||||
95 | {TPM_ALG_CTR, {0, | 1, | 0, | 0, | 0, | 0, | 1, | 0, | 0}}, |
96 | #endif | ||||||||
97 | #ifdef TPM_ALG_OFB | ||||||||
98 | {TPM_ALG_OFB, {0, | 1, | 0, | 0, | 0, | 0, | 1, | 0, | 0}}, |
99 | #endif | ||||||||
100 | #ifdef TPM_ALG_CBC | ||||||||
101 | {TPM_ALG_CBC, {0, | 1, | 0, | 0, | 0, | 0, | 1, | 0, | 0}}, |
102 | #endif | ||||||||
103 | #ifdef TPM_ALG_CFB | ||||||||
104 | {TPM_ALG_CFB, {0, | 1, | 0, | 0, | 0, | 0, | 1, | 0, | 0}}, |
105 | #endif | ||||||||
106 | #ifdef TPM_ALG_ECB | ||||||||
107 | {TPM_ALG_ECB, {0, | 1, | 0, | 0, | 0, | 0, | 1, | 0, | 0}}, |
108 | #endif | ||||||||
109 | }; |
52 | #ifdef TPM_ALG_SM4 | |
53 | {TPM_ALG_SM4, | {0, 1, 0, 0, 0, 0, 0, 0, 0}}, |
54 | #endif | |
55 | #ifdef TPM_ALG_RSASSA | |
56 | {TPM_ALG_RSASSA, | {1, 0, 0, 0, 0, 1, 0, 0, 0}}, |
57 | #endif | |
58 | #ifdef TPM_ALG_RSAES | |
59 | {TPM_ALG_RSAES, | {1, 0, 0, 0, 0, 0, 1, 0, 0}}, |
60 | #endif | |
61 | #ifdef TPM_ALG_RSAPSS | |
62 | {TPM_ALG_RSAPSS, | {1, 0, 0, 0, 0, 1, 0, 0, 0}}, |
63 | #endif | |
64 | #ifdef TPM_ALG_OAEP | |
65 | {TPM_ALG_OAEP, | {1, 0, 0, 0, 0, 0, 1, 0, 0}}, |
66 | #endif | |
67 | #ifdef TPM_ALG_ECDSA | |
68 | {TPM_ALG_ECDSA, | {1, 0, 0, 0, 0, 1, 0, 1, 0}}, |
69 | #endif | |
70 | #ifdef TPM_ALG_ECDH | |
71 | {TPM_ALG_ECDH, | {1, 0, 0, 0, 0, 0, 0, 1, 0}}, |
72 | #endif | |
73 | #ifdef TPM_ALG_ECDAA | |
74 | {TPM_ALG_ECDAA, | {1, 0, 0, 0, 0, 1, 0, 0, 0}}, |
75 | #endif | |
76 | #ifdef TPM_ALG_ECSCHNORR | |
77 | {TPM_ALG_ECSCHNORR, | {1, 0, 0, 0, 0, 1, 0, 0, 0}}, |
78 | #endif |
This function is used by TPM2_GetCapability() to return a list of the implemented algorithms.
Return Value | Meaning |
YES | more algorithms to report |
NO | no more algorithms to report |
TPMI_YES_NO
AlgorithmCapGetImplemented(
TPM_ALG_ID algID, // IN: the starting algorithm ID
UINT32 count, // IN: count of returned algorithms
TPML_ALG_PROPERTY *algList // OUT: algorithm list
115 )
116 {
TPMI_YES_NO more = NO;
UINT32 i;
UINT32 algNum; 120
// initialize output algorithm list
algList->count = 0; 123
// The maximum count of algorithms we may return is MAX_CAP_ALGS.
if(count > MAX_CAP_ALGS)
count = MAX_CAP_ALGS; 127
// Compute how many algorithms are defined in s_algorithms array.
algNum = sizeof(s_algorithms) / sizeof(s_algorithms[0]); 130
// Scan the implemented algorithm list to see if there is a match to 'algID'.
for(i = 0; i < algNum; i++)
133 {
// If algID is less than the starting algorithm ID, skip it
if(s_algorithms[i].algID < algID)
continue;
if(algList->count < count)
138 {
// If we have not filled up the return list, add more algorithms
// to it
algList->algProperties[algList->count].alg = s_algorithms[i].algID;
algList->algProperties[algList->count].algProperties =
s_algorithms[i].attributes;
algList->count++;
145 }
146 else
147 {
// If the return list is full but we still have algorithms
// available, report this and stop scanning.
more = YES;
break;
152 }
153
154 }
155
156 return more; 157
158 }
LIB_EXPORT
void
AlgorithmGetImplementedVector(
ALGORITHM_VECTOR *implemented // OUT: the implemented bits are SET
163 )
164 {
165 int index;
166
// Nothing implemented until we say it is
MemorySet(implemented, 0, sizeof(ALGORITHM_VECTOR));
169 | ||
170 | for(index = (sizeof(s_algorithms) / sizeof(s_algorithms[0])) - 1; | |
171 | index >= 0; | |
172 | index--) | |
173 | SET_BIT(s_algorithms[index].algID, *implemented); | |
174 | return; | |
175 | } |
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.
#include "InternalRoutines.h"
This function is used to check the setting of a bit in an array of bits.
Return Value | Meaning |
TRUE | bit is set |
FALSE | bit is not set |
BOOL
BitIsSet(
unsigned int bitNum, // IN: number of the bit in 'bArray'
BYTE *bArray, // IN: array containing the bit
unsigned int arraySize // IN: size in bytes of 'bArray' 7 )
8 {
pAssert(arraySize > (bitNum >> 3));
return((bArray[bitNum >> 3] & (1 << (bitNum & 7))) != 0); 11 }
This function will set the indicated bit in bArray.
void
BitSet(
unsigned int bitNum, // IN: number of the bit in 'bArray'
BYTE *bArray, // IN: array containing the bit
unsigned int arraySize // IN: size in bytes of 'bArray' 17 )
18 {
pAssert(arraySize > bitNum/8);
bArray[bitNum >> 3] |= (1 << (bitNum & 7));
21 }
This function will clear the indicated bit in bArray.
void
BitClear(
unsigned int bitNum, // IN: number of the bit in 'bArray'.
BYTE *bArray, // IN: array containing the bit
unsigned int arraySize // IN: size in bytes of 'bArray' 27 )
28 {
pAssert(arraySize > bitNum/8);
bArray[bitNum >> 3] &= ~(1 << (bitNum & 7)); 31 }
This is the command code attribute array for GetCapability(). Both this array and s_commandAttributes
provides command code attributes, but tuned for different purpose
1 static const TPMA_CC s_ccAttr [] = {
2 | {0x011f, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_UndefineSpaceSpecial |
3 | {0x0120, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_EvictControl |
4 | {0x0121, | 0, | 1, | 1, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_HierarchyControl |
5 | {0x0122, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_UndefineSpace |
6 | {0x0123, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | No command |
7 | {0x0124, | 0, | 1, | 1, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ChangeEPS |
8 | {0x0125, | 0, | 1, | 1, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ChangePPS |
9 | {0x0126, | 0, | 1, | 1, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Clear |
10 | {0x0127, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ClearControl |
11 | {0x0128, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ClockSet |
12 | {0x0129, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_HierarchyChangeAuth |
13 | {0x012a, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_NV_DefineSpace |
14 | {0x012b, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_Allocate |
15 | {0x012c, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_SetAuthPolicy |
16 | {0x012d, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PP_Commands |
17 | {0x012e, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_SetPrimaryPolicy |
18 | {0x012f, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_FieldUpgradeStart |
19 | {0x0130, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ClockRateAdjust |
20 | {0x0131, | 0, | 0, | 0, | 0, | 1, | 1, | 0, | 0}, | // | TPM_CC_CreatePrimary |
21 | {0x0132, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_NV_GlobalWriteLock |
22 | {0x0133, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_GetCommandAuditDigest |
23 | {0x0134, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_Increment |
24 | {0x0135, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_SetBits |
25 | {0x0136, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_Extend |
26 | {0x0137, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_Write |
27 | {0x0138, | 0, | 1, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_WriteLock |
28 | {0x0139, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_DictionaryAttackLockReset |
29 | {0x013a, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_DictionaryAttackParameters |
30 | {0x013b, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_NV_ChangeAuth |
31 | {0x013c, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_Event |
32 | {0x013d, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_Reset |
33 | {0x013e, | 0, | 0, | 0, | 1, | 1, | 0, | 0, | 0}, | // | TPM_CC_SequenceComplete |
34 | {0x013f, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_SetAlgorithmSet |
35 | {0x0140, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_SetCommandCodeAuditStatus |
36 | {0x0141, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_FieldUpgradeData |
37 | {0x0142, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_IncrementalSelfTest |
38 | {0x0143, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_SelfTest |
39 | {0x0144, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_Startup |
40 | {0x0145, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_Shutdown |
41 | {0x0146, | 0, | 1, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_StirRandom |
42 | {0x0147, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_ActivateCredential |
43 | {0x0148, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_Certify |
44 | {0x0149, | 0, | 0, | 0, | 0, | 3, | 0, | 0, | 0}, | // | TPM_CC_PolicyNV |
45 | {0x014a, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_CertifyCreation |
46 | {0x014b, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_Duplicate |
47 | {0x014c, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_GetTime |
48 | {0x014d, | 0, | 0, | 0, | 0, | 3, | 0, | 0, | 0}, | // | TPM_CC_GetSessionAuditDigest |
49 | {0x014e, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_Read |
50 | {0x014f, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_NV_ReadLock |
51 | {0x0150, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_ObjectChangeAuth |
52 | {0x0151, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_PolicySecret |
53 | {0x0152, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_Rewrap |
54 | {0x0153, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Create |
55 | {0x0154, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ECDH_ZGen |
56 | {0x0155, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_HMAC |
57 | {0x0156, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Import |
58 | {0x0157, | 0, | 0, | 0, | 0, | 1, | 1, | 0, | 0}, | // | TPM_CC_Load |
59 | {0x0158, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Quote |
60 | {0x0159, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_RSA_Decrypt |
61 | {0x015a, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | No command |
62 | {0x015b, | 0, | 0, | 0, | 0, | 1, | 1, | 0, | 0}, | // | TPM_CC_HMAC_Start |
63 | {0x015c, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_SequenceUpdate |
64 | {0x015d, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Sign |
65 | {0x015e, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_Unseal |
66 | {0x015f, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | No command |
67 | {0x0160, | 0, | 0, | 0, | 0, | 2, | 0, | 0, | 0}, | // | TPM_CC_PolicySigned |
68 | {0x0161, | 0, | 0, | 0, | 0, | 0, | 1, | 0, | 0}, | // | TPM_CC_ContextLoad |
69 | {0x0162, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ContextSave |
70 | {0x0163, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ECDH_KeyGen |
71 | {0x0164, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_EncryptDecrypt |
72 | {0x0165, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_FlushContext |
73 | {0x0166, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | No command |
74 | {0x0167, | 0, | 0, | 0, | 0, | 0, | 1, | 0, | 0}, | // | TPM_CC_LoadExternal |
75 | {0x0168, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_MakeCredential |
76 | {0x0169, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_NV_ReadPublic |
77 | {0x016a, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyAuthorize |
78 | {0x016b, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyAuthValue |
79 | {0x016c, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyCommandCode |
80 | {0x016d, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyCounterTimer |
81 | {0x016e, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyCpHash |
82 | {0x016f, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyLocality |
83 | {0x0170, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyNameHash |
84 | {0x0171, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyOR |
85 | {0x0172, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyTicket |
86 | {0x0173, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_ReadPublic |
87 | {0x0174, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_RSA_Encrypt |
88 | {0x0175, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | No command |
89 | {0x0176, | 0, | 0, | 0, | 0, | 2, | 1, | 0, | 0}, | // | TPM_CC_StartAuthSession |
90 | {0x0177, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_VerifySignature |
91 | {0x0178, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_ECC_Parameters |
92 | {0x0179, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_FirmwareRead |
93 | {0x017a, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_GetCapability |
94 | {0x017b, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_GetRandom |
95 | {0x017c, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_GetTestResult |
96 | {0x017d, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_Hash |
97 | {0x017e, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_PCR_Read |
98 | {0x017f, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyPCR |
99 | {0x0180, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyRestart |
100 | {0x0181, | 0, | 0, | 0, | 0, | 0, | 0, | 0, | 0}, | // | TPM_CC_ReadClock |
101 | {0x0182, | 0, | 1, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_Extend |
102 | {0x0183, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PCR_SetAuthValue |
103 | {0x0184, | 0, | 0, | 0, | 0, | 3, | 0, | 0, | 0}, | // | TPM_CC_NV_Certify |
104 | {0x0185, | 0, | 1, | 0, | 1, | 2, | 0, | 0, | 0}, | // | TPM_CC_EventSequenceComplete |
105 | {0x0186, | 0, | 0, | 0, | 0, | 0, | 1, | 0, | 0}, | // | TPM_CC_HashSequenceStart |
106 | {0x0187, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyPhysicalPresence |
107 | {0x0188, | 0, | 0, | 0, | 0, | 1, | 0, | 0, | 0}, | // | TPM_CC_PolicyDuplicationSelect |
108 {0x0189, 0, 0, 0, 0, 1, 0, 0, 0}, // TPM_CC_PolicyGetDigest
109 {0x018a, 0, 0, 0, 0, 0, 0, 0, 0}, // TPM_CC_TestParms
110 {0x018b, 0, 0, 0, 0, 1, 0, 0, 0}, // TPM_CC_Commit
111 {0x018c, 0, 0, 0, 0, 1, 0, 0, 0}, // TPM_CC_PolicyPassword
112 {0x018d, 0, 0, 0, 0, 1, 0, 0, 0}, // TPM_CC_ZGen_2Phase
113 {0x018e, 0, 0, 0, 0, 0, 0, 0, 0}, // TPM_CC_EC_Ephemeral
114 {0x018f, 0, 0, 0, 0, 1, 0, 0, 0} // TPM_CC_PolicyNvWritten
115 };
typedef UINT16 _ATTR_;
#define NOT_IMPLEMENTED (_ATTR_)(0)
#define ENCRYPT_2 (_ATTR_)(1 << 0)
#define ENCRYPT_4 (_ATTR_)(1 << 1)
#define DECRYPT_2 (_ATTR_)(1 << 2)
#define DECRYPT_4 (_ATTR_)(1 << 3)
#define HANDLE_1_USER (_ATTR_)(1 << 4)
#define HANDLE_1_ADMIN (_ATTR_)(1 << 5)
#define HANDLE_1_DUP (_ATTR_)(1 << 6)
#define HANDLE_2_USER (_ATTR_)(1 << 7)
#define PP_COMMAND (_ATTR_)(1 << 8)
#define IS_IMPLEMENTED (_ATTR_)(1 << 9)
#define NO_SESSIONS (_ATTR_)(1 << 10)
#define NV_COMMAND (_ATTR_)(1 << 11)
#define PP_REQUIRED (_ATTR_)(1 << 12)
#define R_HANDLE (_ATTR_)(1 << 13)
This is the command code attribute structure.
132 | typedef UINT16 COMMAND_ATTRIBUTES; | ||
133 | static const COMMAND_ATTRIBUTES s_commandAttributes [] = { | ||
134 | (_ATTR_)(CC_NV_UndefineSpaceSpecial * | ||
(IS_IMPLEMENTED+HANDLE_1_ADMIN+HANDLE_2_USER+PP_COMMAND)), | // | 0x011f | |
135 | (_ATTR_)(CC_EvictControl * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), | // | 0x0120 | |
136 | (_ATTR_)(CC_HierarchyControl * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), | // | 0x0121 | |
137 | (_ATTR_)(CC_NV_UndefineSpace * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), | // | 0x0122 | |
138 | (_ATTR_) (NOT_IMPLEMENTED), |
// 0x0123 - Not assigned
(_ATTR_)(CC_ChangeEPS * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0124
(_ATTR_)(CC_ChangePPS * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0125
(_ATTR_)(CC_Clear * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0126
(_ATTR_)(CC_ClearControl * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0127
(_ATTR_)(CC_ClockSet * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0128
(_ATTR_)(CC_HierarchyChangeAuth *
(IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)), | // | 0x0129 | |
145 | (_ATTR_)(CC_NV_DefineSpace * | ||
(IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)), | // | 0x012a | |
146 | (_ATTR_)(CC_PCR_Allocate * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), | // | 0x012b | |
147 | (_ATTR_)(CC_PCR_SetAuthPolicy * | ||
(IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)), | // | 0x012c | |
148 | (_ATTR_)(CC_PP_Commands * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_REQUIRED)), | // | 0x012d | |
149 | (_ATTR_)(CC_SetPrimaryPolicy * | ||
(IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND)), | // | 0x012e | |
150 | (_ATTR_)(CC_FieldUpgradeStart * | ||
(IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+PP_COMMAND)), | // | 0x012f | |
151 | (_ATTR_)(CC_ClockRateAdjust * | ||
(IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), | // | 0x0130 |
(_ATTR_)(CC_CreatePrimary * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+PP_COMMAND+ENCRYPT_2+R_HANDLE)), // 0x0131
(_ATTR_)(CC_NV_GlobalWriteLock * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0132
(_ATTR_)(CC_GetCommandAuditDigest * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)), // 0x0133
(_ATTR_)(CC_NV_Increment * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x0134
(_ATTR_)(CC_NV_SetBits * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x0135
(_ATTR_)(CC_NV_Extend * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x0136
(_ATTR_)(CC_NV_Write * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x0137
(_ATTR_)(CC_NV_WriteLock * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x0138
(_ATTR_)(CC_DictionaryAttackLockReset * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x0139
(_ATTR_)(CC_DictionaryAttackParameters * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x013a
(_ATTR_)(CC_NV_ChangeAuth * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN)), // 0x013b
(_ATTR_)(CC_PCR_Event * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x013c
(_ATTR_)(CC_PCR_Reset * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x013d
(_ATTR_)(CC_SequenceComplete * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x013e
(_ATTR_)(CC_SetAlgorithmSet * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x013f
(_ATTR_)(CC_SetCommandCodeAuditStatus * (IS_IMPLEMENTED+HANDLE_1_USER+PP_COMMAND)), // 0x0140
(_ATTR_)(CC_FieldUpgradeData * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0141
(_ATTR_)(CC_IncrementalSelfTest * (IS_IMPLEMENTED)),
// 0x0142
(_ATTR_)(CC_SelfTest * (IS_IMPLEMENTED)),
// 0x0143
(_ATTR_)(CC_Startup * (IS_IMPLEMENTED+NO_SESSIONS)),
// 0x0144
(_ATTR_)(CC_Shutdown * (IS_IMPLEMENTED)),
// 0x0145
(_ATTR_)(CC_StirRandom * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0146
(_ATTR_)(CC_ActivateCredential * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+HANDLE_2_USER+ENCRYPT_2)), // 0x0147
(_ATTR_)(CC_Certify * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+HANDLE_2_USER+ENCRYPT_2)), // 0x0148
(_ATTR_)(CC_PolicyNV * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x0149
(_ATTR_)(CC_CertifyCreation * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x014a
(_ATTR_)(CC_Duplicate * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_DUP+ENCRYPT_2)), // 0x014b
(_ATTR_)(CC_GetTime * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)), // 0x014c
(_ATTR_)(CC_GetSessionAuditDigest * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)), // 0x014d
(_ATTR_)(CC_NV_Read * (IS_IMPLEMENTED+HANDLE_1_USER+ENCRYPT_2)), // 0x014e
(_ATTR_)(CC_NV_ReadLock * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x014f
(_ATTR_)(CC_ObjectChangeAuth * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_ADMIN+ENCRYPT_2)), // 0x0150
(_ATTR_)(CC_PolicySecret * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0151
(_ATTR_)(CC_Rewrap * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0152
(_ATTR_)(CC_Create * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0153
(_ATTR_)(CC_ECDH_ZGen * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0154
(_ATTR_)(CC_HMAC * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0155
(_ATTR_)(CC_Import * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0156
(_ATTR_)(CC_Load * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2+R_HANDLE)), // 0x0157
(_ATTR_)(CC_Quote * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0158
(_ATTR_)(CC_RSA_Decrypt * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x0159
(_ATTR_) (NOT_IMPLEMENTED),
// 0x015a - Not assigned
(_ATTR_)(CC_HMAC_Start * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+R_HANDLE)), // 0x015b
(_ATTR_)(CC_SequenceUpdate * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x015c
(_ATTR_)(CC_Sign * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x015d
(_ATTR_)(CC_Unseal * (IS_IMPLEMENTED+HANDLE_1_USER+ENCRYPT_2)), // 0x015e
(_ATTR_) (NOT_IMPLEMENTED),
// 0x015f - Not assigned
(_ATTR_)(CC_PolicySigned * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2)),
// 0x0160
(_ATTR_)(CC_ContextLoad * (IS_IMPLEMENTED+NO_SESSIONS+R_HANDLE)),
// 0x0161
(_ATTR_)(CC_ContextSave * (IS_IMPLEMENTED+NO_SESSIONS)),
// 0x0162
(_ATTR_)(CC_ECDH_KeyGen * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x0163
(_ATTR_)(CC_EncryptDecrypt * (IS_IMPLEMENTED+HANDLE_1_USER+ENCRYPT_2)), // 0x0164
(_ATTR_)(CC_FlushContext * (IS_IMPLEMENTED+NO_SESSIONS)),
// 0x0165
(_ATTR_) (NOT_IMPLEMENTED),
// 0x0166 - Not assigned
(_ATTR_)(CC_LoadExternal * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2+R_HANDLE)), // 0x0167
(_ATTR_)(CC_MakeCredential * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2)),
// 0x0168
(_ATTR_)(CC_NV_ReadPublic * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x0169
(_ATTR_)(CC_PolicyAuthorize * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x016a
(_ATTR_)(CC_PolicyAuthValue * (IS_IMPLEMENTED)),
// 0x016b
(_ATTR_)(CC_PolicyCommandCode * (IS_IMPLEMENTED)),
// 0x016c
(_ATTR_)(CC_PolicyCounterTimer * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x016d
(_ATTR_)(CC_PolicyCpHash * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x016e
(_ATTR_)(CC_PolicyLocality * (IS_IMPLEMENTED)),
// 0x016f
(_ATTR_)(CC_PolicyNameHash * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0170
(_ATTR_)(CC_PolicyOR * (IS_IMPLEMENTED)),
// 0x0171
(_ATTR_)(CC_PolicyTicket * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0172
(_ATTR_)(CC_ReadPublic * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x0173
(_ATTR_)(CC_RSA_Encrypt * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2)),
// 0x0174
(_ATTR_) (NOT_IMPLEMENTED),
// 0x0175 - Not assigned
(_ATTR_)(CC_StartAuthSession * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2+R_HANDLE)), // 0x0176
(_ATTR_)(CC_VerifySignature * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0177
(_ATTR_)(CC_ECC_Parameters * (IS_IMPLEMENTED)),
// 0x0178
(_ATTR_)(CC_FirmwareRead * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x0179
(_ATTR_)(CC_GetCapability * (IS_IMPLEMENTED)),
// 0x017a
(_ATTR_)(CC_GetRandom * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x017b
(_ATTR_)(CC_GetTestResult * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x017c
(_ATTR_)(CC_Hash * (IS_IMPLEMENTED+DECRYPT_2+ENCRYPT_2)),
// 0x017d
(_ATTR_)(CC_PCR_Read * (IS_IMPLEMENTED)),
// 0x017e
(_ATTR_)(CC_PolicyPCR * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x017f
(_ATTR_)(CC_PolicyRestart * (IS_IMPLEMENTED)),
// 0x0180
(_ATTR_)(CC_ReadClock * (IS_IMPLEMENTED+NO_SESSIONS)),
// 0x0181
(_ATTR_)(CC_PCR_Extend * (IS_IMPLEMENTED+HANDLE_1_USER)),
// 0x0182
(_ATTR_)(CC_PCR_SetAuthValue * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER)), // 0x0183
(_ATTR_)(CC_NV_Certify * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER+ENCRYPT_2)), // 0x0184
(_ATTR_)(CC_EventSequenceComplete * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+HANDLE_2_USER)), // 0x0185
(_ATTR_)(CC_HashSequenceStart * (IS_IMPLEMENTED+DECRYPT_2+R_HANDLE)),
// 0x0186
(_ATTR_)(CC_PolicyPhysicalPresence * (IS_IMPLEMENTED)),
// 0x0187
(_ATTR_)(CC_PolicyDuplicationSelect * (IS_IMPLEMENTED+DECRYPT_2)),
// 0x0188
(_ATTR_)(CC_PolicyGetDigest * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x0189
(_ATTR_)(CC_TestParms * (IS_IMPLEMENTED)),
// 0x018a
(_ATTR_)(CC_Commit * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x018b
(_ATTR_)(CC_PolicyPassword * (IS_IMPLEMENTED)),
// 0x018c
(_ATTR_)(CC_ZGen_2Phase * (IS_IMPLEMENTED+DECRYPT_2+HANDLE_1_USER+ENCRYPT_2)), // 0x018d
(_ATTR_)(CC_EC_Ephemeral * (IS_IMPLEMENTED+ENCRYPT_2)),
// 0x018e
(_ATTR_)(CC_PolicyNvWritten * (IS_IMPLEMENTED))
// 0x018f
247 };
This file contains the functions for testing various command properties.
#include "Tpm.h"
#include "InternalRoutines.h"
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 their is no ambiguity about the table containing the information being the normative definition.
#include "CommandAttributeData.c"
This function returns the authorization role required of a handle.
Return Value | Meaning |
AUTH_NONE | no authorization is required |
AUTH_USER | user role authorization is required |
AUTH_ADMIN | admin role authorization is required |
AUTH_DUP | duplication role authorization is required |
AUTH_ROLE
CommandAuthRole(
TPM_CC commandCode, // IN: command code
UINT32 handleIndex // IN: handle index (zero based) 9 )
10 {
if(handleIndex > 1)
return AUTH_NONE;
if(handleIndex == 0) {
ATTRIBUTE_TYPE properties = s_commandAttributes[commandCode - TPM_CC_FIRST];
if(properties & HANDLE_1_USER) return AUTH_USER;
if(properties & HANDLE_1_ADMIN) return AUTH_ADMIN;
if(properties & HANDLE_1_DUP) return AUTH_DUP;
return AUTH_NONE; 19 }
if(s_commandAttributes[commandCode - TPM_CC_FIRST] & HANDLE_2_USER) return AUTH_USER;
return AUTH_NONE; 22 }
This function indicates if a command is implemented.
Return Value | Meaning |
TRUE | if the command is implemented |
FALSE | if the command is not implemented |
BOOL
CommandIsImplemented(
TPM_CC commandCode // IN: command code 26 )
27 {
if(commandCode < TPM_CC_FIRST || commandCode > TPM_CC_LAST)
return FALSE;
if((s_commandAttributes[commandCode - TPM_CC_FIRST] & IS_IMPLEMENTED))
return TRUE;
else
return FALSE; 34 }
return a TPMA_CC structure for the given command code
TPMA_CC
CommandGetAttribute(
TPM_CC commandCode // IN: command code 38 )
39 {
UINT32 size = sizeof(s_ccAttr) / sizeof(s_ccAttr[0]);
UINT32 i;
for(i = 0; i < size; i++) {
if(s_ccAttr[i].commandIndex == (UINT16) commandCode)
return s_ccAttr[i]; 45 }
46
// This function should be called in the way that the command code
// attribute is available.
FAIL(FATAL_ERROR_INTERNAL); 50 }
This function returns the size of the decrypt size field. This function returns 0 if encryption is not allowed
Return Value | Meaning |
0 | encryption not allowed |
2 | size field is two bytes |
4 | size field is four bytes |
int
EncryptSize(
TPM_CC commandCode // IN: commandCode 54 )
55 {
COMMAND_ATTRIBUTES ca = s_commandAttributes[commandCode - TPM_CC_FIRST];
if(ca & ENCRYPT_2)
return 2;
if(ca & ENCRYPT_4)
return 4;
return 0;
62 }
This function returns the size of the decrypt size field. This function returns 0 if decryption is not allowed
Return Value | Meaning |
0 | encryption not allowed |
2 | size field is two bytes |
4 | size field is four bytes |
int
DecryptSize(
TPM_CC commandCode // IN: commandCode 66 )
67 {
68 COMMAND_ATTRIBUTES ca = s_commandAttributes[commandCode - TPM_CC_FIRST]; 69
if(ca & DECRYPT_2)
return 2;
if(ca & DECRYPT_4)
return 4;
return 0; 75 }
This function indicates if the command is allowed to have sessions.
This function must not be called if the command is not known to be implemented.
Return Value | Meaning |
TRUE | session is allowed with this command |
FALSE | session is not allowed with this command |
BOOL
IsSessionAllowed(
TPM_CC commandCode // IN: the command to be checked 79 )
80 {
if(s_commandAttributes[commandCode - TPM_CC_FIRST] & NO_SESSIONS)
return FALSE;
else
return TRUE; 85 }
BOOL
IsHandleInResponse(
TPM_CC commandCode 89 )
90 {
if(s_commandAttributes[commandCode - TPM_CC_FIRST] & R_HANDLE)
return TRUE;
else
return FALSE;
95 }
Checks to see if an operation will write to NV memory
BOOL
IsWriteOperation(
TPM_CC command // IN: Command to check 99 )
100 {
101 switch (command)
102 {
case TPM_CC_NV_Write:
case TPM_CC_NV_Increment:
case TPM_CC_NV_SetBits:
case TPM_CC_NV_Extend:
// Nv write lock counts as a write operation for authorization purposes.
// We check to see if the NV is write locked before we do the authorization
// If it is locked, we fail the command early.
case TPM_CC_NV_WriteLock:
return TRUE;
default:
break;
114 }
115 return FALSE;
116 }
Checks to see if an operation will write to NV memory
BOOL
IsReadOperation(
TPM_CC command // IN: Command to check
120 )
121 {
122 switch (command)
123 {
case TPM_CC_NV_Read:
case TPM_CC_PolicyNV:
case TPM_CC_NV_Certify:
// Nv read lock counts as a read operation for authorization purposes.
// We check to see if the NV is read locked before we do the authorization
// If it is locked, we fail the command early.
case TPM_CC_NV_ReadLock:
return TRUE;
default:
break;
134 }
135 return FALSE;
136 }
This function returns a list of implemented commands and command attributes starting from the command in commandCode.
Return Value | Meaning |
YES | more command attributes are available |
NO | no more command attributes are available |
TPMI_YES_NO
CommandCapGetCCList(
TPM_CC commandCode, // IN: start command code
UINT32 count, // IN: maximum count for number of entries in
// 'commandList'
TPML_CCA *commandList // OUT: list of TPMA_CC
143 )
144 {
TPMI_YES_NO more = NO;
UINT32 i; 147
// initialize output handle list count
commandList->count = 0; 150
// The maximum count of commands that may be return is MAX_CAP_CC.
if(count > MAX_CAP_CC) count = MAX_CAP_CC; 153
// If the command code is smaller than TPM_CC_FIRST, start from TPM_CC_FIRST
if(commandCode < TPM_CC_FIRST) commandCode = TPM_CC_FIRST; 156
// Collect command attributes
for(i = commandCode; i <= TPM_CC_LAST; i++)
159 {
160 if(CommandIsImplemented(i))
161 {
162 if(commandList->count < count)
163 {
// If the list is not full, add the attributes for this command.
commandList->commandAttributes[commandList->count]
166 = CommandGetAttribute(i);
167 commandList->count++;
168 }
169 else
170 {
// If the list is full but there are more commands to report,
// indicate this and return.
more = YES;
break;
175 }
176 }
177 }
178 return more;
179 }
This file contains functions that simulate the DRTM events. Its primary purpose is to isolate the name space of the simulator from the name space of the TPM. This is only an issue with the parameters to
_TPM_Hash_Data().
1 #include "InternalRoutines.h"
This function interfaces between the platform code and _TPM_Hash_Start().
LIB_EXPORT void
Signal_Hash_Start(
void
5 )
6 {
_TPM_Hash_Start();
return; 9 }
This function interfaces between the platform code and _TPM_Hash_Data().
LIB_EXPORT void
Signal_Hash_Data(
unsigned int size,
unsigned char *buffer
14 )
15 {
_TPM_Hash_Data(size, buffer);
return; 18 }
This function interfaces between the platform code and _TPM_Hash_End().
LIB_EXPORT void
Signal_Hash_End(
void
22 )
23 {
_TPM_Hash_End();
return; 26 }
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.
#include "InternalRoutines.h"
This function will indicate if the entity associated with a handle is present in TPM memory. If the handle is a persistent object handle, and the object exists, the persistent object is moved from NV memory into a RAM object slot and the persistent handle is replaced with the transient object handle for the slot.
Error Returns | Meaning |
TPM_RC_HANDLE | handle type does not match |
TPM_RC_REFERENCE_H0 | entity is not present |
TPM_RC_HIERARCHY | entity belongs to a disabled hierarchy |
TPM_RC_OBJECT_MEMORY | handle is an evict object but there is no space to load it to RAM |
TPM_RC
EntityGetLoadStatus(
TPM_HANDLE *handle, // IN/OUT: handle of the entity
TPM_CC commandCode // IN: the commmandCode 6 )
7 {
8 TPM_RC result = TPM_RC_SUCCESS; 9
10 switch(HandleGetType(*handle)) 11 {
// For handles associated with hierarchies, the entity is present
// only if the associated enable is SET.
case TPM_HT_PERMANENT:
switch(*handle)
16 {
case TPM_RH_OWNER:
if(!gc.shEnable)
result = TPM_RC_HIERARCHY;
break;
21
#ifdef VENDOR_PERMANENT
case VENDOR_PERMANENT:
#endif
case TPM_RH_ENDORSEMENT:
if(!gc.ehEnable)
result = TPM_RC_HIERARCHY;
break;
case TPM_RH_PLATFORM:
if(!g_phEnable)
result = TPM_RC_HIERARCHY;
break;
// null handle, PW session handle and lockout
// handle are always available
case TPM_RH_NULL:
case TPM_RS_PW:
case TPM_RH_LOCKOUT:
break;
default:
// handling of the manufacture_specific handles
if( ((TPM_RH)*handle >= TPM_RH_AUTH_00)
&& ((TPM_RH)*handle <= TPM_RH_AUTH_FF))
// use the value that would have been returned from
// unmarshaling if it did the handle filtering
result = TPM_RC_VALUE;
else
pAssert(FALSE);
break;
49 | } | ||
50 | break; | ||
51 | case TPM_HT_TRANSIENT: | ||
52 | // For a transient object, check if the handle is associated | ||
53 | // with a loaded object. | ||
54 | if(!ObjectIsPresent(*handle)) | ||
55 | result = TPM_RC_REFERENCE_H0; | ||
56 | break; | ||
57 | case TPM_HT_PERSISTENT: | ||
58 | // Persistent object | ||
59 | // Copy the persistent object to RAM and replace the handle with | the | |
60 | // handle of the assigned slot. A TPM_RC_OBJECT_MEMORY, | ||
61 | // TPM_RC_HIERARCHY or TPM_RC_REFERENCE_H0 error may be returned | by | |
62 | // ObjectLoadEvict() | ||
63 | result = ObjectLoadEvict(handle, commandCode); | ||
64 | break; | ||
65 | case TPM_HT_HMAC_SESSION: | ||
66 | // For an HMAC session, see if the session is loaded | ||
67 | // and if the session in the session slot is actually | ||
68 | // an HMAC session. | ||
69 | if(SessionIsLoaded(*handle)) | ||
70 | { | ||
71 | SESSION *session; | ||
72 | session = SessionGet(*handle); | ||
73 | // Check if the session is a HMAC session | ||
74 | if(session->attributes.isPolicy == SET) | ||
75 | result = TPM_RC_HANDLE; | ||
76 | } | ||
77 | else | ||
78 | result = TPM_RC_REFERENCE_H0; | ||
79 | break; | ||
80 | case TPM_HT_POLICY_SESSION: | ||
81 | // For a policy session, see if the session is loaded | ||
82 | // and if the session in the session slot is actually | ||
83 | // a policy session. | ||
84 | if(SessionIsLoaded(*handle)) | ||
85 | { | ||
86 | SESSION *session; | ||
87 | session = SessionGet(*handle); | ||
88 | // Check if the session is a policy session | ||
89 | if(session->attributes.isPolicy == CLEAR) | ||
90 | result = TPM_RC_HANDLE; | ||
91 | } | ||
92 | else | ||
93 | result = TPM_RC_REFERENCE_H0; | ||
94 | break; | ||
95 | case TPM_HT_NV_INDEX: | ||
96 | // For an NV Index, use the platform-specific routine | ||
97 | // to search the IN Index space. | ||
98 | result = NvIndexIsAccessible(*handle, commandCode); | ||
99 | break; | ||
100 | case TPM_HT_PCR: | ||
101 | // Any PCR handle that is unmarshaled successfully referenced | ||
102 | // a PCR that is defined. | ||
103 | break; | ||
104 | default: | ||
105 | // Any other handle type is a defect in the unmarshaling code. | ||
106 | pAssert(FALSE); | ||
107 | break; | ||
108 | } | ||
109 | return result; | ||
110 | } |
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. Return value is the number of octets copied to auth.
UINT16
EntityGetAuthValue(
TPMI_DH_ENTITY handle, // IN: handle of entity
AUTH_VALUE *auth // OUT: authValue of the entity
115 )
116 {
117 TPM2B_AUTH authValue = {0}; 118
119 switch(HandleGetType(handle))
120 {
case TPM_HT_PERMANENT:
switch(handle)
123 {
case TPM_RH_OWNER:
// ownerAuth for TPM_RH_OWNER
authValue = gp.ownerAuth;
break;
case TPM_RH_ENDORSEMENT:
// endorsementAuth for TPM_RH_ENDORSEMENT
authValue = gp.endorsementAuth;
break;
case TPM_RH_PLATFORM:
// platformAuth for TPM_RH_PLATFORM
authValue = gc.platformAuth;
break;
case TPM_RH_LOCKOUT:
// lockoutAuth for TPM_RH_LOCKOUT
authValue = gp.lockoutAuth;
break;
case TPM_RH_NULL:
// nullAuth for TPM_RH_NULL. Return 0 directly here
return 0;
break;
#ifdef VENDOR_PERMANENT
case VENDOR_PERMANENT:
// vendor auth value
authValue = g_platformUniqueDetails;
#endif
default:
// If any other permanent handle is present it is
// a code defect.
pAssert(FALSE);
break;
154 }
break;
case TPM_HT_TRANSIENT:
// authValue for an object
// A persistent object would have been copied into RAM
// and would have an transient object handle here.
160 {
OBJECT *object;
object = ObjectGet(handle);
// special handling if this is a sequence object
if(ObjectIsSequence(object))
165 | { | |
166 | authValue = ((HASH_OBJECT *)object)->auth; | |
167 | } | |
168 | else | |
169 | { | |
170 | // Auth value is available only when the private portion of | |
171 | // the object is loaded. The check should be made before | |
172 | // this function is called | |
173 | pAssert(object->attributes.publicOnly == CLEAR); | |
174 | authValue = object->sensitive.authValue; | |
175 | } | |
176 | } | |
177 | break; | |
178 | case TPM_HT_NV_INDEX: | |
179 | // authValue for an NV index | |
180 | { | |
181 | NV_INDEX nvIndex; | |
182 | NvGetIndexInfo(handle, &nvIndex); | |
183 | authValue = nvIndex.authValue; | |
184 | } | |
185 | break; | |
186 | case TPM_HT_PCR: | |
187 | // authValue for PCR | |
188 | PCRGetAuthValue(handle, &authValue); | |
189 | break; | |
190 | default: | |
191 | // If any other handle type is present here, then there is a defect | |
192 | // in the unmarshaling code. | |
193 | pAssert(FALSE); | |
194 | break; | |
195 | } | |
196 |
// Copy the authValue
pAssert(authValue.t.size <= sizeof(authValue.t.buffer));
MemoryCopy(auth, authValue.t.buffer, authValue.t.size, sizeof(TPMU_HA)); 200
201 return authValue.t.size;
202 }
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.
TPMI_ALG_HASH
EntityGetAuthPolicy(
TPMI_DH_ENTITY handle, // IN: handle of entity
TPM2B_DIGEST *authPolicy // OUT: authPolicy of the entity
207 )
208 {
209 TPMI_ALG_HASH hashAlg = TPM_ALG_NULL; 210
211 switch(HandleGetType(handle))
212 {
case TPM_HT_PERMANENT:
switch(handle)
215 {
case TPM_RH_OWNER:
// ownerPolicy for TPM_RH_OWNER
*authPolicy = gp.ownerPolicy;
hashAlg = gp.ownerAlg;
break;
case TPM_RH_ENDORSEMENT:
// endorsementPolicy for TPM_RH_ENDORSEMENT
*authPolicy = gp.endorsementPolicy;
hashAlg = gp.endorsementAlg;
break;
case TPM_RH_PLATFORM:
// platformPolicy for TPM_RH_PLATFORM
*authPolicy = gc.platformPolicy;
hashAlg = gc.platformAlg;
break;
case TPM_RH_LOCKOUT:
// lockoutPolicy for TPM_RH_LOCKOUT
*authPolicy = gp.lockoutPolicy;
hashAlg = gp.lockoutAlg;
break;
default:
// If any other permanent handle is present it is
// a code defect.
pAssert(FALSE);
break;
241 }
break;
case TPM_HT_TRANSIENT:
// authPolicy for an object
245 {
OBJECT *object = ObjectGet(handle);
*authPolicy = object->publicArea.authPolicy;
hashAlg = object->publicArea.nameAlg;
249 }
break;
case TPM_HT_NV_INDEX:
// authPolicy for a NV index
253 {
NV_INDEX nvIndex;
NvGetIndexInfo(handle, &nvIndex);
*authPolicy = nvIndex.publicArea.authPolicy;
hashAlg = nvIndex.publicArea.nameAlg;
258 }
break;
case TPM_HT_PCR:
// authPolicy for a PCR
hashAlg = PCRGetAuthPolicy(handle, authPolicy);
break;
default:
// If any other handle type is present it is a code defect.
pAssert(FALSE);
break;
268 }
269 return hashAlg;
270 }
This function returns the Name associated with a handle. It will set name to the Name and return the size of the Name string.
UINT16
EntityGetName(
TPMI_DH_ENTITY handle, // IN: handle of entity
NAME *name // OUT: name of entity
275 | ) | |
276 | { | |
277 | UINT16 nameSize; | |
278 | ||
279 | switch(HandleGetType(handle)) | |
280 | { | |
281 | case TPM_HT_TRANSIENT: | |
282 | // Name for an object | |
283 | nameSize = ObjectGetName(handle, name); | |
284 | break; | |
285 | case TPM_HT_NV_INDEX: | |
286 | // Name for a NV index | |
287 | nameSize = NvGetName(handle, name); | |
288 | break; | |
289 | default: | |
290 | // For all other types, the handle is the Name | |
291 | nameSize = TPM_HANDLE_Marshal(&handle, (BYTE **)&name, NULL); | |
292 | break; | |
293 | } | |
294 | return nameSize; | |
295 | } |
This function returns the hierarchy handle associated with an entity.
A handle that is a hierarchy handle is associated with itself.
An NV index belongs to TPM_RH_PLATFORM if TPMA_NV_PLATFORMCREATE, is SET, otherwise it belongs to TPM_RH_OWNER
An object handle belongs to its hierarchy. All other handles belong to the platform hierarchy. or an NV Index.
TPMI_RH_HIERARCHY
EntityGetHierarchy(
TPMI_DH_ENTITY handle // IN :handle of entity
299 )
300 {
301 TPMI_RH_HIERARCHY hierarcy = TPM_RH_NULL; 302
303 switch(HandleGetType(handle))
304 {
case TPM_HT_PERMANENT:
// hierarchy for a permanent handle
switch(handle)
308 {
case TPM_RH_PLATFORM:
case TPM_RH_ENDORSEMENT:
case TPM_RH_NULL:
hierarcy = handle;
break;
// all other permanent handles are associated with the owner
// hierarchy. (should only be TPM_RH_OWNER and TPM_RH_LOCKOUT)
default:
hierarcy = TPM_RH_OWNER;
break;
319 }
break;
case TPM_HT_NV_INDEX:
// hierarchy for NV index
323 {
NV_INDEX nvIndex;
NvGetIndexInfo(handle, &nvIndex);
// If only the platform can delete the index, then it is
327 | // considered to be in the platform hierarchy, otherwise it | ||
328 | // is in the owner hierarchy. | ||
329 | if(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == | SET) | |
330 | hierarcy = TPM_RH_PLATFORM; | ||
331 | else | ||
332 | hierarcy = TPM_RH_OWNER; | ||
333 | } | ||
334 | break; | ||
335 | case TPM_HT_TRANSIENT: | ||
336 | // hierarchy for an object | ||
337 | { | ||
338 | OBJECT *object; | ||
339 | object = ObjectGet(handle); | ||
340 | if(object->attributes.ppsHierarchy) | ||
341 | { | ||
342 | hierarcy = TPM_RH_PLATFORM; | ||
343 | } | ||
344 | else if(object->attributes.epsHierarchy) | ||
345 | { | ||
346 | hierarcy = TPM_RH_ENDORSEMENT; | ||
347 | } | ||
348 | else if(object->attributes.spsHierarchy) | ||
349 | { | ||
350 | hierarcy = TPM_RH_OWNER; | ||
351 | } | ||
352 | |||
353 | } | ||
354 | break; | ||
355 | case TPM_HT_PCR: | ||
356 | hierarcy = TPM_RH_OWNER; | ||
357 | break; | ||
358 | default: | ||
359 | pAssert(0); | ||
360 | break; | ||
361 | } | ||
362 | // this is unreachable but it provides a return value for the default | ||
363 | // case which makes the complier happy | ||
364 | return hierarcy; | ||
365 | } |
This file will instance the TPM variables that are not stack allocated. The descriptions for these variables is in Global.h.
#define GLOBAL_C
#include "InternalRoutines.h"
These values are visible across multiple modules.
BOOL g_phEnable;
const UINT16 g_rcIndex[15] = {TPM_RC_1, TPM_RC_2, TPM_RC_3, TPM_RC_4,
TPM_RC_5, TPM_RC_6, TPM_RC_7, TPM_RC_8,
TPM_RC_9, TPM_RC_A, TPM_RC_B, TPM_RC_C,
TPM_RC_D, TPM_RC_E, TPM_RC_F
8 | }; | |
9 | TPM_HANDLE | g_exclusiveAuditSession; |
10 | UINT64 | g_time; |
11 | BOOL | g_pcrReConfig; |
12 | TPMI_DH_OBJECT | g_DRTMHandle; |
13 | BOOL | g_DrtmPreStartup; |
14 | BOOL | g_StartupLocality3; |
15 | BOOL | g_clearOrderly; |
16 | TPM_SU | g_prevOrderlyState; |
17 | BOOL | g_updateNV; |
18 | BOOL | g_nvOk; |
19 | TPM2B_AUTH | g_platformUniqueDetails; |
20 | STATE_CLEAR_DATA | gc; |
21 | STATE_RESET_DATA | gr; |
22 | PERSISTENT_DATA | gp; |
23 | ORDERLY_DATA | go; |
#ifndef IGNORE_STATE
// DO NOT DEFINE THIS VALUE
These values do not need to be retained between commands.
TPM_HANDLE s_sessionHandles[MAX_SESSION_NUM];
TPMA_SESSION s_attributes[MAX_SESSION_NUM];
TPM_HANDLE s_associatedHandles[MAX_SESSION_NUM];
TPM2B_NONCE s_nonceCaller[MAX_SESSION_NUM];
TPM2B_AUTH s_inputAuthValues[MAX_SESSION_NUM];
UINT32 s_encryptSessionIndex;
UINT32 s_decryptSessionIndex;
UINT32 s_auditSessionIndex;
TPM2B_DIGEST s_cpHashForAudit;
UINT32 s_sessionNum;
#endif // IGNORE_STATE
BOOL s_DAPendingOnNV;
#ifdef TPM_CC_GetCommandAuditDigest
TPM2B_DIGEST s_cpHashForCommandAudit;
#endif
UINT64 s_selfHealTimer;
UINT64 s_lockoutTimer;
UINT32 s_reservedAddr[NV_RESERVE_LAST];
UINT32 s_reservedSize[NV_RESERVE_LAST];
UINT32 s_ramIndexSize;
BYTE s_ramIndex[RAM_INDEX_SPACE];
UINT32 s_ramIndexSizeAddr;
UINT32 s_ramIndexAddr;
UINT32 s_maxCountAddr;
UINT32 s_evictNvStart;
UINT32 s_evictNvEnd;
TPM_RC s_NvStatus;
OBJECT_SLOT s_objects[MAX_LOADED_OBJECTS];
PCR s_pcrs[IMPLEMENTATION_PCR];
SESSION_SLOT s_sessions[MAX_LOADED_SESSIONS];
UINT32 s_oldestSavedSession;
int s_freeSessionSlots;
BOOL g_manufactured = FALSE;
BOOL s_initialized = FALSE;
The s_actionOutputBuffer should not be modifiable by the host system until the TPM has returned a response code. The s_actionOutputBuffer should not be accessible until response parameter encryption, if any, is complete. This memory is not used between commands
#ifndef IGNORE_STATE
// DO NOT DEFINE THIS VALUE
UINT32 s_actionInputBuffer[1024]; // action input buffer
UINT32 s_actionOutputBuffer[1024]; // action output buffer
BYTE s_responseBuffer[MAX_RESPONSE_SIZE];// response buffer
#endif
Define these values here if the AlgorithmTests() project is not used
#ifndef SELF_TEST
ALGORITHM_VECTOR g_implementedAlgorithms;
ALGORITHM_VECTOR g_toTest;
#endif
jmp_buf g_jumpBuffer;
BOOL g_forceFailureMode;
BOOL g_inFailureMode;
UINT32 s_failFunction;
UINT32 s_failLine;
UINT32 s_failCode;
This file contains the functions that return the type of a handle.
#include "Tpm.h"
#include "InternalRoutines.h"
This function returns the type of a handle which is the MSO of the handle.
TPM_HT
HandleGetType(
TPM_HANDLE handle // IN: a handle to be checked 6 )
7 {
// return the upper bytes of input data
return (TPM_HT) ((handle & HR_RANGE_MASK) >> HR_SHIFT); 10 }
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:
Return Value | Meaning |
TPM_HANDLE
NextPermanentHandle(
TPM_HANDLE inHandle // IN: the handle to check 14 )
15 {
// If inHandle is below the start of the range of permanent handles
// set it to the start and scan from there
if(inHandle < TPM_RH_FIRST)
inHandle = TPM_RH_FIRST;
// scan from input value untill we find an implemented permanent handle
// or go out of range
for(; inHandle <= TPM_RH_LAST; inHandle++) 23 {
24 switch (inHandle)
25 {
case TPM_RH_OWNER:
case TPM_RH_NULL:
case TPM_RS_PW:
case TPM_RH_LOCKOUT:
case TPM_RH_ENDORSEMENT:
case TPM_RH_PLATFORM:
case TPM_RH_PLATFORM_NV:
#ifdef VENDOR_PERMANENT
case VENDOR_PERMANENT:
#endif
return inHandle;
37 | break; | |
38 | default: | |
39 | break; | |
40 | } | |
41 | } | |
42 | // Out of range on the top | |
43 | return 0; | |
44 | } |
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.
Return Value | Meaning |
YES | if there are more handles available |
NO | all the available handles has been returned |
TPMI_YES_NO
PermanentCapGetHandles(
TPM_HANDLE handle, // IN: start handle
UINT32 count, // IN: count of returned handle
TPML_HANDLE *handleList // OUT: list of handle 50 )
51 {
TPMI_YES_NO more = NO;
UINT32 i; 54
55 pAssert(HandleGetType(handle) == TPM_HT_PERMANENT); 56
// Initialize output handle list
handleList->count = 0; 59
// The maximum count of handles we may return is MAX_CAP_HANDLES
if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; 62
// Iterate permanent handle range
for(i = NextPermanentHandle(handle);
i != 0; i = NextPermanentHandle(i+1)) 66 {
67 if(handleList->count < count)
68 {
// If we have not filled up the return list, add this permanent
// handle to it
handleList->handle[handleList->count] = i;
handleList->count++; 73 }
74 else
75 {
// If the return list is full but we still have permanent handle
// available, report this and stop iterating
more = YES;
break;
80 }
81 }
82 return more; 83 }
#include "InternalRoutines.h"
This function will convert a locality expressed as an integer into TPMA_LOCALITY form. The function returns the locality attribute.
TPMA_LOCALITY
LocalityGetAttributes(
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 | locality_attributes.TPM_LOC_ZERO = SET; | |
15 | break; | |
16 | case 1: | |
17 | locality_attributes.TPM_LOC_ONE = SET; | |
18 | break; | |
19 | case 2: | |
20 | locality_attributes.TPM_LOC_TWO = SET; | |
21 | break; | |
22 | case 3: | |
23 | locality_attributes.TPM_LOC_THREE = SET; | |
24 | break; | |
25 | case 4: | |
26 | locality_attributes.TPM_LOC_FOUR = SET; | |
27 | break; | |
28 | default: | |
29 | pAssert(locality < 256 && locality > 31); | |
30 | *localityAsByte = locality; | |
31 | break; | |
32 | } | |
33 | return locality_attributes; | |
34 | } |
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.
Includes and Data Definitions
#define MANUFACTURE_C
#include "InternalRoutines.h"
#include "Global.h"
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.
Return Value | Meaning |
0 | success |
1 | manufacturing process previously performed |
LIB_EXPORT int
TPM_Manufacture(
BOOL firstTime // IN: indicates if this is the first call from 7 // main()
8 )
9 {
TPM_SU orderlyShutdown;
UINT64 totalResetCount = 0; 12
// If TPM has been manufactured, return indication.
if(!firstTime && g_manufactured)
return 1;
16
// initialize crypto units
//CryptInitUnits(); 19
20 //
s_selfHealTimer = 0;
s_lockoutTimer = 0;
s_DAPendingOnNV = FALSE; 24
// initialize NV
NvInit(); 27
#ifdef _DRBG_STATE_SAVE
// Initialize the drbg. This needs to come before the install
// of the hierarchies
if(!_cpri Startup()) // Have to start the crypto units first
FAIL(FATAL_ERROR_INTERNAL);
_cpri DrbgGetPutState(PUT_STATE, 0, NULL);
#endif 35
// default configuration for PCR
PCRSimStart(); 38
// initialize pre-installed hierarchy data
// This should happen after NV is initialized because hierarchy data is
// stored in NV.
HierarchyPreInstall_Init(); 43
// initialize dictionary attack parameters
DAPreInstall_Init(); 46
// initialize PP list
PhysicalPresencePreInstall_Init(); 49
// initialize command audit list
CommandAuditPreInstall_Init(); 52
53 // first start up is required to be Startup(CLEAR)
orderlyShutdown = TPM_SU_CLEAR;
NvWriteReserved(NV_ORDERLY, &orderlyShutdown); 56
// initialize the firmware version
gp.firmwareV1 = FIRMWARE_V1;
#ifdef FIRMWARE_V2
gp.firmwareV2 = FIRMWARE_V2;
#else
gp.firmwareV2 = 0;
#endif
NvWriteReserved(NV_FIRMWARE_V1, &gp.firmwareV1);
NvWriteReserved(NV_FIRMWARE_V2, &gp.firmwareV2); 66
// initialize the total reset counter to 0
NvWriteReserved(NV_TOTAL_RESET_COUNT, &totalResetCount); 69
// initialize the clock stuff
go.clock = 0;
go.clockSafe = YES; 73
#ifdef _DRBG_STATE_SAVE
// initialize the current DRBG state in NV 76
_cpri DrbgGetPutState(GET_STATE, sizeof(go.drbgState), (BYTE *)&go.drbgState);
#endif 79
80 NvWriteReserved(NV_ORDERLY_DATA, &go); 81
// Commit NV writes. Manufacture process is an artificial process existing
// only in simulator environment and it is not defined in the specification
// that what should be the expected behavior if the NV write fails at this
// point. Therefore, it is assumed the NV write here is always success and
// no return code of this function is checked.
NvCommit(); 88
89 g_manufactured = TRUE; 90
91 return 0; 92 }
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.
Return Value | Meaning |
0 | success |
1 | TPM not previously manufactured |
LIB_EXPORT int
TPM_TearDown(
void
96 )
97 {
// stop crypt units
CryptStopUnits(); 100
g_manufactured = FALSE;
return 0;
103 }
This file contains the marshaling and unmarshaling code.
The marshaling and unmarshaling code and function prototypes are not listed, as the code is repetitive, long, and not very useful to read. Examples of a few unmarshaling routines are provided. Most of the others are similar.
Depending on the table header flags, a type will have an unmarshaling routine and a marshaling routine The table header flags that control the generation of the unmarshaling and marshaling code are delimited by angle brackets ("<>") in the table header. If no brackets are present, then both unmarshaling and marshaling code is generated (i.e., generation of both marshaling and unmarshaling code is the default).
Unmarshal and Marshal a Value
In TPM 2.0 Part 2, a TPMI_DI_OBJECT is defined by this table:
Table xxx — Definition of (TPM_HANDLE) TPMI_DH_OBJECT Type
Values | Comments |
{TRANSIENT_FIRST:TRANSIENT_LAST} | allowed range for transient objects |
{PERSISTENT_FIRST:PERSISTENT_LAST} | allowed range for persistent objects |
+TPM_RH_NULL | the null handle |
#TPM_RC_VALUE |
This generates the following unmarshaling code:
TPM_RC
TPMI_DH_OBJECT_Unmarshal(TPMI_DH_OBJECT *target, BYTE **buffer, INT32 *size,
bool flag)
4 {
TPM_RC result;
result = TPM_HANDLE_Unmarshal((TPM_HANDLE *)target, buffer, size);
if(result != TPM_RC_SUCCESS)
return result;
if (*target == TPM_RH_NULL) {
if(flag)
return TPM_RC_SUCCESS;
else
return TPM_RC_VALUE; 14 }
if((*target < TRANSIENT_FIRST) || (*target > TRANSIENT_LAST))
if((*target < PERSISTENT_FIRST) || (*target > PERSISTENT_LAST))
return TPM_RC_VALUE;
return TPM_RC_SUCCESS; 19 }
and the following marshaling code:
NOTE The marshaling code does not do parameter checking, as the TPM is the source of the marshaling data.
UINT16
TPMI_DH_OBJECT_Marshal(TPMI_DH_OBJECT *source, BYTE **buffer, INT32 *size) 3 {
4 return UINT32_Marshal((UINT32 *)source, buffer, size); 5 }
Unmarshal and Marshal a Union
In TPM 2.0 Part 2, a TPMU_PUBLIC_PARMS union is defined by:
Table xxx — Definition of TPMU_PUBLIC_PARMS Union <IN/OUT, S>
Parameter | Type | Selector | Description |
keyedHash | TPMS_KEYEDHASH_PARMS | TPM_ALG_KEYEDHASH | sign | encrypt | neither |
symDetail | TPMT_SYM_DEF_OBJECT | TPM_ALG_SYMCIPHER | a symmetric block cipher |
rsaDetail | TPMS_RSA_PARMS | TPM_ALG_RSA | decrypt + sign |
eccDetail | TPMS_ECC_PARMS | TPM_ALG_ECC | decrypt + sign |
asymDetail | TPMS_ASYM_PARMS | common scheme structure for RSA and ECC keys | |
NOTE The Description column indicates which of TPMA_OBJECT.decrypt or TPMA_OBJECT.sign may be set. “+” indicates that both may be set but one shall be set. “|” indicates the optional settings. |
From this table, the following unmarshaling code is generated.
TPM_RC
TPMU_PUBLIC_PARMS_Unmarshal(TPMU_PUBLIC_PARMS *target, BYTE **buffer, INT32 *size,
UINT32 selector)
4 {
switch(selector) {
#ifdef TPM_ALG_KEYEDHASH
case TPM_ALG_KEYEDHASH:
return TPMS_KEYEDHASH_PARMS_Unmarshal(
(TPMS_KEYEDHASH_PARMS *)&(target->keyedHash), buffer, size);
#endif
#ifdef TPM_ALG_SYMCIPHER
case TPM_ALG_SYMCIPHER:
return TPMT_SYM_DEF_OBJECT_Unmarshal(
(TPMT_SYM_DEF_OBJECT *)&(target->symDetail), buffer, size, FALSE);
#endif
#ifdef TPM_ALG_RSA
case TPM_ALG_RSA:
return TPMS_RSA_PARMS_Unmarshal(
(TPMS_RSA_PARMS *)&(target->rsaDetail), buffer, size);
#endif
#ifdef TPM_ALG_ECC
case TPM_ALG_ECC:
return TPMS_ECC_PARMS_Unmarshal(
(TPMS_ECC_PARMS *)&(target->eccDetail), buffer, size);
#endif
26 }
27 return TPM_RC_SELECTOR; 28 }
NOTE The #ifdef/#endif directives are added whenever a value is dependent on an algorithm ID so that removing the algorithm definition will remove the related code.
The marshaling code for the union is:
UINT16
TPMU_PUBLIC_PARMS_Marshal(TPMU_PUBLIC_PARMS *source, BYTE **buffer, INT32 *size,
UINT32 selector)
4 {
switch(selector) {
#ifdef TPM_ALG_KEYEDHASH
case TPM_ALG_KEYEDHASH:
return TPMS_KEYEDHASH_PARMS_Marshal(
(TPMS_KEYEDHASH_PARMS *)&(source->keyedHash), buffer, size);
#endif
#ifdef TPM_ALG_SYMCIPHER
case TPM_ALG_SYMCIPHER:
return TPMT_SYM_DEF_OBJECT_Marshal(
(TPMT_SYM_DEF_OBJECT *)&(source->symDetail), buffer, size);
#endif
#ifdef TPM_ALG_RSA
case TPM_ALG_RSA:
return TPMS_RSA_PARMS_Marshal(
(TPMS_RSA_PARMS *)&(source->rsaDetail), buffer, size);
#endif
#ifdef TPM_ALG_ECC
case TPM_ALG_ECC:
return TPMS_ECC_PARMS_Marshal(
(TPMS_ECC_PARMS *)&(source->eccDetail), buffer, size);
#endif
26 }
assert(1);
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.
Unmarshal and Marshal a Structure
In TPM 2.0 Part 2, the TPMT_PUBLiC structure is defined by:
Table xxx — Definition of TPMT_PUBLIC Structure
Parameter | Type | Description |
type | TPMI_ALG_PUBLIC | “algorithm” associated with this object |
nameAlg | +TPMI_ALG_HASH | algorithm used for computing the Name of the object NOTE The "+" indicates that the instance of a TPMT_PUBLIC may have a "+" to indicate that the nameAlg may be TPM_ALG_NULL. |
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 |
[type]parameters | TPMU_PUBLIC_PARMS | the algorithm or structure details |
[type]unique | TPMU_PUBLIC_ID | the unique identifier of the structure For an asymmetric key, this would be the public key. |
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:
TPM_RC
TPMT_PUBLIC_Unmarshal(TPMT_PUBLIC *target, BYTE **buffer, INT32 *size, bool flag) 3 {
TPM_RC result;
result = TPMI_ALG_PUBLIC_Unmarshal((TPMI_ALG_PUBLIC *)&(target->type),
buffer, size);
if(result != TPM_RC_SUCCESS)
return result;
result = TPMI_ALG_HASH_Unmarshal((TPMI_ALG_HASH *)&(target->nameAlg),
buffer, size, flag);
if(result != TPM_RC_SUCCESS)
return result;
result = TPMA_OBJECT_Unmarshal((TPMA_OBJECT *)&(target->objectAttributes),
buffer, size);
if(result != TPM_RC_SUCCESS)
return result;
result = TPM2B_DIGEST_Unmarshal((TPM2B_DIGEST *)&(target->authPolicy),
buffer, size);
if(result != TPM_RC_SUCCESS)
return result; 21
result = TPMU_PUBLIC_PARMS_Unmarshal((TPMU_PUBLIC_PARMS *)&(target->parameters),
buffer, size, );
if(result != TPM_RC_SUCCESS)
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 | } |
)
The marshaling code for the TPMT_PUBLIC structure is:
UINT16
TPMT_PUBLIC_Marshal(TPMT_PUBLIC *source, BYTE **buffer, INT32 *size) 3 {
UINT16 result = 0;
result = (UINT16)(result + TPMI_ALG_PUBLIC_Marshal(
(TPMI_ALG_PUBLIC *)&(source->type), buffer, size));
result = (UINT16)(result + TPMI_ALG_HASH_Marshal(
(TPMI_ALG_HASH *)&(source->nameAlg), buffer, size)) 9 ;
result = (UINT16)(result + TPMA_OBJECT_Marshal(
(TPMA_OBJECT *)&(source->objectAttributes), buffer, size)); 12
result = (UINT16)(result + TPM2B_DIGEST_Marshal(
(TPM2B_DIGEST *)&(source->authPolicy), buffer, size)); 15
result = (UINT16)(result + TPMU_PUBLIC_PARMS_Marshal(
(TPMU_PUBLIC_PARMS *)&(source->parameters), buffer, size, 18 ));
19
result = (UINT16)(result + TPMU_PUBLIC_ID_Marshal(
(TPMU_PUBLIC_ID *)&(source->unique), buffer, size, 22 ));
23
24 return result; 25 }
Unmarshal and Marshal an Array
In TPM 2.0 Part 2, the TPML_DIGEST is defined by:
Table xxx — Definition of TPML_DIGEST Structure
Parameter | Type | Description |
count {2:} | UINT32 | number of digests in the list, minimum is two |
digests[count]{:8} | TPM2B_DIGEST | a list of digests For TPM2_PolicyOR(), all digests will have been computed using the digest of the policy session. For TPM2_PCR_Read(), each digest will be the size of the digest for the bank containing the PCR. |
#TPM_RC_SIZE | response code when count is not at least two or is greater than 8 |
The digests parameter is an array of up to count structures (TPM2B_DIGESTS). The auto-generated code to Unmarshal this structure is:
TPM_RC
TPML_DIGEST_Unmarshal(TPML_DIGEST *target, BYTE **buffer, INT32 *size) 3 {
TPM_RC result;
result = UINT32_Unmarshal((UINT32 *)&(target->count), buffer, size);
if(result != TPM_RC_SUCCESS)
return result; 8
9 if( (target->count < 2)) // This check is triggered by the {2:} notation
// on ‘count’
return TPM_RC_SIZE; 12
if((target->count) > 8) // This check is triggered by the {:8} notation
// on ‘digests’.
return TPM_RC_SIZE; 16
result = TPM2B_DIGEST_Array_Unmarshal((TPM2B_DIGEST *)(target->digests),
buffer, size, );
if(result != TPM_RC_SUCCESS)
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:
TPM_RC
TPM2B_DIGEST_Array_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size,
INT32 count)
4 {
TPM_RC result;
INT32 i;
for(i = 0; i < count; i++) {
result = TPM2B_DIGEST_Unmarshal(&target[i], buffer, size);
if(result != TPM_RC_SUCCESS)
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.
UINT16
TPML_DIGEST_Marshal(TPML_DIGEST *source, BYTE **buffer, INT32 *size) 3 {
UINT16 result = 0;
result = (UINT16)(result + UINT32_Marshal((UINT32 *)&(source->count), buffer,
size));
result = (UINT16)(result + TPM2B_DIGEST_Array_Marshal(
(TPM2B_DIGEST *)(source->digests), buffer, size,
(INT32)(source->count)));
10
11 return result; 12 }
The marshaling code for the array is:
TPM_RC
TPM2B_DIGEST_Array_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size,
INT32 count)
4 {
TPM_RC result;
INT32 i;
for(i = 0; i < count; i++) {
result = TPM2B_DIGEST_Unmarshal(&target[i], buffer, size);
if(result != TPM_RC_SUCCESS)
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
10.11.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.
Table xxx — Definition of TPM2B_EVENT Structure
Parameter | Type | Description |
size | UINT16 | Size of the operand |
buffer [size] {:1024} | BYTE | The operand |
TPM_RC
TPM2B_EVENT_Unmarshal(TPM2B_EVENT *target, BYTE **buffer, INT32 *size) 3 {
TPM_RC result;
result = UINT16_Unmarshal((UINT16 *)&(target->t.size), buffer, size);
if(result != TPM_RC_SUCCESS)
return result; 8
9 // if size equal to 0, the rest of the structure is a zero buffer. Stop processing
10 | if(target->t.size == 0) | ||
11 | return TPM_RC_SUCCESS; | ||
12 | |||
13 | if((target->t.size) > 1024) // This check is triggered | by the {:1024} notation | |
14 | // on ‘buffer’ | ||
15 | return TPM_RC_SIZE; | ||
16 | |||
17 | result = BYTE_Array_Unmarshal((BYTE *)(target->t.buffer), | buffer, size, | |
18 | (INT32)(target->t.size)); | ||
19 | if(result != TPM_RC_SUCCESS) | ||
20 | return result; | ||
21 | |||
22 | return TPM_RC_SUCCESS; | ||
23 | } |
Which use these structure definitions:
typedef struct {
UINT16 size;
BYTE buffer[1];
} TPM2B; 5
typedef struct {
UINT16 size;
BYTE buffer[1024];
} EVENT_2B; 10
typedef union {
EVENT_2B t; // The type-specific union member
TPM2B b; // The generic union member
} TPM2B_EVENT;
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 in the TPM in order to avoid namespace contamination.
Includes and Data Definitions
#define MEMORY_LIB_C
#include "InternalRoutines.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. However, the s_actionInputBuffer and s_responseBuffer are not needed at the same time and they could be the same buffer.
This function moves data from one place in memory to another. No safety checks of any type are performed. If source and data buffer overlap, then the move is done as if an intermediate buffer were used.
NOTE: This function is used by MemoryCopy(), MemoryCopy2B(), and MemoryConcat2b() and requires that the caller know the maximum size of the destination buffer so that there is no possibility of buffer overrun.
LIB_EXPORT void
MemoryMove(
void *destination, // OUT: move destination
const void *source, // IN: move source
UINT32 size, // IN: number of octets to moved
UINT32 dSize // IN: size of the receive buffer 9 )
10 {
const BYTE *p = (BYTE *)source;
BYTE *q = (BYTE *)destination; 13
if(destination == NULL || source == NULL)
return;
16
pAssert(size <= dSize);
// if the destination buffer has a lower address than the
// source, then moving bytes in ascending order is safe.
dSize -= size; 21
22 if (p>q || (p+size <= q))
23 {
24 while(size--) 25 *q++ = *p++;
26 }
// If the destination buffer has a higher address than the
// source, then move bytes from the end to the beginning.
else if (p < q)
30 {
p += size;
q += size;
33 | while (size--) | |
34 | *--q = *--p; | |
35 | } | |
36 | ||
37 | // If the source and destination address are the same, nothing to move. | |
38 | return; | |
39 | } |
This function moves data from one place in memory to another. No safety checks of any type are performed. If the destination and source overlap, then the results are unpredictable. void MemoryCopy(
void | *destination, // OUT: copy destination |
void | *source, // IN: copy source |
UINT32 | size, // IN: number of octets being copied |
UINT32 | dSize // IN: size of the receive buffer |
MemoryMove(destination, source, size, dSize);
//%#define MemoryCopy(destination, source, size, destSize) \
//% MemoryMove((destination), (source), (size), (destSize))
This function indicates if two buffers have the same values in the indicated number of bytes.
Return Value | Meaning |
TRUE | all octets are the same |
FALSE | all octets are not the same |
LIB_EXPORT BOOL
MemoryEqual(
const void *buffer1, // IN: compare buffer1
const void *buffer2, // IN: compare buffer2
UINT32 size // IN: size of bytes being compared 47 )
48 {
BOOL equal = TRUE;
const BYTE *b1, *b2; 51
b1 = (BYTE *)buffer1;
b2 = (BYTE *)buffer2; 54
// Compare all bytes so that there is no leakage of information
// due to timing differences.
for(; size > 0; size--)
58 equal = (*b1++ == *b2++) && equal; 59
60 return equal; 61 }
This function copies a TPM2B. This can be used when the TPM2B types are the same or different. No size checking is done on the destination so the caller should make sure that the destination is large enough.
This function returns the number of octets in the data buffer of the TPM2B.
LIB_EXPORT INT16
MemoryCopy2B(
TPM2B *dest, // OUT: receiving TPM2B
const TPM2B *source, // IN: source TPM2B
UINT16 dSize // IN: size of the receiving buffer 67 )
68 {
69
if(dest == NULL)
return 0;
if(source == NULL)
dest->size = 0;
else
75 {
dest->size = source->size;
MemoryMove(dest->buffer, source->buffer, dest->size, dSize); 78 }
79 return dest->size; 80 }
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)).
LIB_EXPORT void
MemoryConcat2B(
TPM2B *aInOut, // IN/OUT: destination 2B
TPM2B *bIn, // IN: second 2B
UINT16 aSize // IN: The size of aInOut.buffer (max values for
// aInOut.size)
87 )
88 {
MemoryMove(&aInOut->buffer[aInOut->size],
bIn->buffer,
bIn->size,
aSize - aInOut->size);
aInOut->size = aInOut->size + bIn->size;
return; 95 }
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.
Return Value | Meaning |
TRUE | size and buffer contents are the same |
FALSE | size or buffer contents are not the same |
96 | LIB_EXPORT BOOL | ||
97 | Memory2BEqual( | ||
98 | const TPM2B | *aIn, | // IN: compare value |
99 | const TPM2B | *bIn | // IN: compare value |
100 | ) | ||
101 | { | ||
102 | if(aIn->size | != bIn->size) |
103 return FALSE;
104
105 return MemoryEqual(aIn->buffer, bIn->buffer, aIn->size);
106 }
This function will set all the octets in the specified memory range to the specified octet value.
NOTE: the dSize parameter forces the caller to know how big the receiving buffer is to make sure that there is no possibility that the caller will inadvertently run over the end of the buffer.
LIB_EXPORT void
MemorySet(
void *destination, // OUT: memory destination
char value, // IN: fill value
UINT32 size // IN: number of octets to fill
112 )
113 {
char *p = (char *)destination;
while (size--)
*p++ = value;
return;
118 }
This function returns the address of the buffer into which the command parameters will be unmarshaled in preparation for calling the command actions.
BYTE *
MemoryGetActionInputBuffer(
UINT32 size // Size, in bytes, required for the input
// unmarshaling
123 )
124 {
125 BYTE *buf = NULL; 126
127 if(size > 0)
128 {
// In this implementation, a static buffer is set aside for action output.
// Other implementations may apply additional optimization based on command
// code or other factors.
UINT32 *p = s_actionInputBuffer;
buf = (BYTE *)p;
pAssert(size < sizeof(s_actionInputBuffer)); 135
// size of an element in the buffer
#define SZ sizeof(s_actionInputBuffer[0]) 138
139 for(size = (size + SZ - 1) / SZ; size > 0; size--) 140 *p++ = 0;
141 #undef SZ
142 }
143 return buf;
144 }
MemoryGetActionOutputBuffer()
This function returns the address of the buffer into which the command action code places its output values.
void *
MemoryGetActionOutputBuffer(
TPM_CC command // Command that requires the buffer
148 )
149 {
// In this implementation, a static buffer is set aside for action output.
// Other implementations may apply additional optimization based on the command
// code or other factors.
command = 0; // Unreferenced parameter
return s_actionOutputBuffer;
155 }
This function returns the address into which the command response is marshaled from values in the action output buffer.
BYTE *
MemoryGetResponseBuffer(
TPM_CC command // Command that requires the buffer
159 )
160 {
// In this implementation, a static buffer is set aside for responses.
// Other implementation may apply additional optimization based on the command
// code or other factors.
command = 0; // Unreferenced parameter
return s_responseBuffer;
166 }
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.
UINT16
MemoryRemoveTrailingZeros (
TPM2B_AUTH *auth // IN/OUT: value to adjust
170 )
171 {
BYTE *a = &auth->t.buffer[auth->t.size-1];
for(; auth->t.size > 0; auth->t.size--)
174 {
175 if(*a--)
176 break;
177 }
178 return auth->t.size;
179 }
This file contains functions that receive the simulated power state transitions of the TPM.
Includes and Data Definitions
#define POWER_C
#include "InternalRoutines.h"
This function is used to process a power on event.
void
TPMInit(
void
6 )
7 {
// Set state as not initialized. This means that Startup is required
s_initialized = FALSE; 10
11 return; 12 }
This function registers the fact that the TPM has been initialized (a TPM2_Startup() has completed successfully).
void
TPMRegisterStartup(
void
16 )
17 {
18 s_initialized = TRUE; 19
20 return; 21 }
Indicates if the TPM has been initialized (a TPM2_Startup() has completed successfully after a
_TPM_Init()).
Return Value | Meaning |
TRUE | TPM has been initialized |
FALSE | TPM has not been initialized |
BOOL
TPMIsStarted(
void
25 )
26 {
27 return s_initialized; 28 }
This file contains the functions that are used for accessing the TPM_CAP_TPM_PROPERTY values.
#include "InternalRoutines.h"
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.
Return Value | Meaning |
TRUE | referenced property exists and value set |
FALSE | referenced property does not exist |
static BOOL
TPMPropertyIsDefined(
TPM_PT property, // IN: property
UINT32 *value // OUT: property value 6 )
7 {
8 switch(property)
9 {
case TPM_PT_FAMILY_INDICATOR:
// from the title page of the specification
// For this specification, the value is "2.0".
*value = TPM_SPEC_FAMILY;
break;
case TPM_PT_LEVEL:
// from the title page of the specification
*value = TPM_SPEC_LEVEL;
break;
case TPM_PT_REVISION:
// from the title page of the specification
*value = TPM_SPEC_VERSION;
break;
case TPM_PT_DAY_OF_YEAR:
// computed from the date value on the title page of the specification
*value = TPM_SPEC_DAY_OF_YEAR;
break;
case TPM_PT_YEAR:
// from the title page of the specification
*value = TPM_SPEC_YEAR;
break;
case TPM_PT_MANUFACTURER:
// vendor ID unique to each TPM manufacturer
*value = BYTE_ARRAY_TO_UINT32(MANUFACTURER);
break;
case TPM_PT_VENDOR_STRING_1:
// first four characters of the vendor ID string
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_1);
break;
case TPM_PT_VENDOR_STRING_2:
// second four characters of the vendor ID string
#ifdef VENDOR_STRING_2
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_2);
#else
*value = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_3:
// third four characters of the vendor ID string
#ifdef VENDOR_STRING_3
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_3);
#else
*value = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_4:
// fourth four characters of the vendor ID string
#ifdef VENDOR_STRING_4
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_4);
#else
*value = 0;
#endif
break;
case TPM_PT_VENDOR_TPM_TYPE:
// vendor-defined value indicating the TPM model
*value = 1;
break;
case TPM_PT_FIRMWARE_VERSION_1:
// more significant 32-bits of a vendor-specific value
*value = gp.firmwareV1;
break;
case TPM_PT_FIRMWARE_VERSION_2:
// less significant 32-bits of a vendor-specific value
*value = gp.firmwareV2;
break;
case TPM_PT_INPUT_BUFFER:
// maximum size of TPM2B_MAX_BUFFER
*value = MAX_DIGEST_BUFFER;
break;
case TPM_PT_HR_TRANSIENT_MIN:
// minimum number of transient objects that can be held in TPM
// RAM
*value = MAX_LOADED_OBJECTS;
break;
case TPM_PT_HR_PERSISTENT_MIN:
// minimum number of persistent objects that can be held in
// TPM NV memory
// In this implementation, there is no minimum number of
// persistent objects.
*value = MIN_EVICT_OBJECTS;
break;
case TPM_PT_HR_LOADED_MIN:
// minimum number of authorization sessions that can be held in
// TPM RAM
*value = MAX_LOADED_SESSIONS;
break;
case TPM_PT_ACTIVE_SESSIONS_MAX:
// number of authorization sessions that may be active at a time
*value = MAX_ACTIVE_SESSIONS;
break;
case TPM_PT_PCR_COUNT:
// number of PCR implemented
*value = IMPLEMENTATION_PCR;
break;
case TPM_PT_PCR_SELECT_MIN:
// minimum number of bytes in a TPMS_PCR_SELECT.sizeOfSelect
*value = PCR_SELECT_MIN;
break;
case TPM_PT_CONTEXT_GAP_MAX:
// maximum allowed difference (unsigned) between the contextID
// values of two saved session contexts
*value = (1 << (sizeof(CONTEXT_SLOT) * 8)) - 1;
break;
case TPM_PT_NV_COUNTERS_MAX:
// maximum number of NV indexes that are allowed to have the
// TPMA_NV_COUNTER attribute SET
// In this implementation, there is no limitation on the number
// of counters, except for the size of the NV Index memory.
*value = 0;
break;
case TPM_PT_NV_INDEX_MAX:
// maximum size of an NV index data area
*value = MAX_NV_INDEX_SIZE;
break;
case TPM_PT_MEMORY:
// a TPMA_MEMORY indicating the memory management method for the TPM
126 {
TPMA_MEMORY attributes = {0};
attributes.sharedNV = SET;
attributes.objectCopiedToRam = SET; 130
// Note: Different compilers may require a different method to cast
// a bit field structure to a UINT32.
*value = * (UINT32 *) &attributes;
break;
135 }
case TPM_PT_CLOCK_UPDATE:
// interval, in seconds, between updates to the copy of
// TPMS_TIME_INFO .clock in NV
*value = (1 << NV_CLOCK_UPDATE_INTERVAL);
break;
case TPM_PT_CONTEXT_HASH:
// algorithm used for the integrity hash on saved contexts and
// for digesting the fuData of TPM2_FirmwareRead()
*value = CONTEXT_INTEGRITY_HASH_ALG;
break;
case TPM_PT_CONTEXT_SYM:
// algorithm used for encryption of saved contexts
*value = CONTEXT_ENCRYPT_ALG;
break;
case TPM_PT_CONTEXT_SYM_SIZE:
// size of the key used for encryption of saved contexts
*value = CONTEXT_ENCRYPT_KEY_BITS;
break;
case TPM_PT_ORDERLY_COUNT:
// maximum difference between the volatile and non-volatile
// versions of TPMA_NV_COUNTER that have TPMA_NV_ORDERLY SET
*value = MAX_ORDERLY_COUNT;
break;
case TPM_PT_MAX_COMMAND_SIZE:
// maximum value for 'commandSize'
*value = MAX_COMMAND_SIZE;
break;
case TPM_PT_MAX_RESPONSE_SIZE:
// maximum value for 'responseSize'
*value = MAX_RESPONSE_SIZE;
break;
case TPM_PT_MAX_DIGEST:
// maximum size of a digest that can be produced by the TPM
*value = sizeof(TPMU_HA);
break;
case TPM_PT_MAX_OBJECT_CONTEXT:
// maximum size of a TPMS_CONTEXT that will be returned by
// TPM2_ContextSave for object context
*value = 0;
175
// adding sequence, saved handle and hierarchy
*value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) +
sizeof(TPMI_RH_HIERARCHY);
// add size field in TPM2B_CONTEXT
*value += sizeof(UINT16); 181
// add integrity hash size
*value += sizeof(UINT16) +
CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG); 185
// Add fingerprint size, which is the same as sequence size
*value += sizeof(UINT64); 188
// Add OBJECT structure size
*value += sizeof(OBJECT);
break;
case TPM_PT_MAX_SESSION_CONTEXT:
// the maximum size of a TPMS_CONTEXT that will be returned by
// TPM2_ContextSave for object context
*value = 0;
196
// adding sequence, saved handle and hierarchy
*value += sizeof(UINT64) + sizeof(TPMI_DH_CONTEXT) +
sizeof(TPMI_RH_HIERARCHY);
// Add size field in TPM2B_CONTEXT
*value += sizeof(UINT16); 202
// Add integrity hash size
*value += sizeof(UINT16) +
CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
// Add fingerprint size, which is the same as sequence size
*value += sizeof(UINT64); 208
// Add SESSION structure size
*value += sizeof(SESSION);
break;
case TPM_PT_PS_FAMILY_INDICATOR:
// platform specific values for the TPM_PT_PS parameters from
// the relevant platform-specific specification
// In this reference implementation, all of these values are 0.
*value = 0;
break;
case TPM_PT_PS_LEVEL:
// level of the platform-specific specification
*value = 0;
break;
case TPM_PT_PS_REVISION:
// specification Revision times 100 for the platform-specific
// specification
*value = 0;
break;
case TPM_PT_PS_DAY_OF_YEAR:
// platform-specific specification day of year using TCG calendar
*value = 0;
break;
case TPM_PT_PS_YEAR:
// platform-specific specification year using the CE
*value = 0;
break;
case TPM_PT_SPLIT_MAX:
// number of split signing operations supported by the TPM
*value = 0;
#ifdef TPM_ALG_ECC
*value = sizeof(gr.commitArray) * 8;
#endif
break;
case TPM_PT_TOTAL_COMMANDS:
// total number of commands implemented in the TPM
// Since the reference implementation does not have any
// vendor-defined commands, this will be the same as the
// number of library commands.
247 {
UINT32 i;
*value = 0;
250
// calculate implemented command numbers
for(i = TPM_CC_FIRST; i <= TPM_CC_LAST; i++)
253 {
254 if(CommandIsImplemented(i)) (*value)++;
255 }
256 break;
257 }
case TPM_PT_LIBRARY_COMMANDS:
// number of commands from the TPM library that are implemented
260 {
UINT32 i;
*value = 0;
263
// calculate implemented command numbers
for(i = TPM_CC_FIRST; i <= TPM_CC_LAST; i++)
266 {
267 if(CommandIsImplemented(i)) (*value)++;
268 }
269 break;
270 }
case TPM_PT_VENDOR_COMMANDS:
// number of vendor commands that are implemented
*value = 0;
break;
case TPM_PT_PERMANENT:
// TPMA_PERMANENT
277 {
TPMA_PERMANENT flags = {0};
if(gp.ownerAuth.t.size != 0)
flags.ownerAuthSet = SET;
if(gp.endorsementAuth.t.size != 0)
flags.endorsementAuthSet = SET;
if(gp.lockoutAuth.t.size != 0)
flags.lockoutAuthSet = SET;
if(gp.disableClear)
flags.disableClear = SET;
if(gp.failedTries >= gp.maxTries)
flags.inLockout = SET;
// In this implementation, EPS is always generated by TPM
flags.tpmGeneratedEPS = SET; 291
// Note: Different compilers may require a different method to cast
// a bit field structure to a UINT32.
*value = * (UINT32 *) &flags;
break;
296 }
case TPM_PT_STARTUP_CLEAR:
// TPMA_STARTUP_CLEAR
299 {
TPMA_STARTUP_CLEAR flags = {0};
if(g_phEnable)
flags.phEnable = SET;
if(gc.shEnable)
flags.shEnable = SET;
if(gc.ehEnable)
flags.ehEnable = SET;
if(gc.phEnableNV)
flags.phEnableNV = SET;
if(g_prevOrderlyState != SHUTDOWN_NONE)
flags.orderly = SET; 311
// Note: Different compilers may require a different method to cast
// a bit field structure to a UINT32.
*value = * (UINT32 *) &flags;
break;
316 }
case TPM_PT_HR_NV_INDEX:
// number of NV indexes currently defined
*value = NvCapGetIndexNumber();
break;
case TPM_PT_HR_LOADED:
// number of authorization sessions currently loaded into TPM
// RAM
*value = SessionCapGetLoadedNumber();
break;
case TPM_PT_HR_LOADED_AVAIL:
// number of additional authorization sessions, of any type,
// that could be loaded into TPM RAM
*value = SessionCapGetLoadedAvail();
break;
case TPM_PT_HR_ACTIVE:
// number of active authorization sessions currently being
// tracked by the TPM
*value = SessionCapGetActiveNumber();
break;
case TPM_PT_HR_ACTIVE_AVAIL:
// number of additional authorization sessions, of any type,
// that could be created
*value = SessionCapGetActiveAvail();
break;
case TPM_PT_HR_TRANSIENT_AVAIL:
// estimate of the number of additional transient objects that
// could be loaded into TPM RAM
*value = ObjectCapGetTransientAvail();
break;
case TPM_PT_HR_PERSISTENT:
// number of persistent objects currently loaded into TPM
// NV memory
*value = NvCapGetPersistentNumber();
break;
case TPM_PT_HR_PERSISTENT_AVAIL:
// number of additional persistent objects that could be loaded
// into NV memory
*value = NvCapGetPersistentAvail();
break;
case TPM_PT_NV_COUNTERS:
// number of defined NV indexes that have NV TPMA_NV_COUNTER
// attribute SET
*value = NvCapGetCounterNumber();
break;
case TPM_PT_NV_COUNTERS_AVAIL:
// number of additional NV indexes that can be defined with their
// TPMA_NV_COUNTER attribute SET
*value = NvCapGetCounterAvail();
break;
case TPM_PT_ALGORITHM_SET:
// region code for the TPM
*value = gp.algorithmSet;
break;
370
case TPM_PT_LOADED_CURVES:
#ifdef TPM_ALG_ECC
// number of loaded ECC curves
*value = CryptCapGetEccCurveNumber();
#else // TPM_ALG_ECC
376 | *value = 0; | |
377 | #endif // TPM_ALG_ECC | |
378 | break; | |
379 | ||
380 | case TPM_PT_LOCKOUT_COUNTER: | |
381 | // current value of the lockout counter | |
382 | *value = gp.failedTries; | |
383 | break; | |
384 | case TPM_PT_MAX_AUTH_FAIL: | |
385 | // number of authorization failures before DA lockout is invoked | |
386 | *value = gp.maxTries; | |
387 | break; | |
388 | case TPM_PT_LOCKOUT_INTERVAL: | |
389 | // number of seconds before the value reported by | |
390 | // TPM_PT_LOCKOUT_COUNTER is decremented | |
391 | *value = gp.recoveryTime; | |
392 | break; | |
393 | case TPM_PT_LOCKOUT_RECOVERY: | |
394 | // number of seconds after a lockoutAuth failure before use of | |
395 | // lockoutAuth may be attempted again | |
396 | *value = gp.lockoutRecovery; | |
397 | break; | |
398 | case TPM_PT_AUDIT_COUNTER_0: | |
399 | // high-order 32 bits of the command audit counter | |
400 | *value = (UINT32) (gp.auditCounter >> 32); | |
401 | break; | |
402 | case TPM_PT_AUDIT_COUNTER_1: | |
403 | // low-order 32 bits of the command audit counter | |
404 | *value = (UINT32) (gp.auditCounter); | |
405 | break; | |
406 | default: | |
407 | // property is not defined | |
408 | return FALSE; | |
409 | break; | |
410 | } | |
411 | ||
412 | return TRUE; | |
413 | } |
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.
Return Value | Meaning |
YES | more properties are available |
NO | no more properties to be reported |
414 | TPMI_YES_NO | ||
415 | TPMCapGetProperties( | ||
416 | TPM_PT property, | // | IN: the starting TPM property |
417 | UINT32 count, | // | IN: maximum number of returned |
418 | // | propertie | |
419 | TPML_TAGGED_TPM_PROPERTY *propertyList | // | OUT: property list |
420 | ) | ||
421 | { | ||
422 | TPMI_YES_NO more = NO; | ||
423 | UINT32 i; | ||
424 | |||
425 | // initialize output property list | ||
426 | propertyList->count = 0; |
427 | ||
428 | // maximum count of properties we may return is MAX_PCR_PROPERTIES | |
429 | if(count > MAX_TPM_PROPERTIES) count = MAX_TPM_PROPERTIES; | |
430 | ||
431 | // If property is less than PT_FIXED, start from PT_FIXED. | |
432 | if(property < PT_FIXED) property = PT_FIXED; | |
433 | ||
434 | // Scan through the TPM properties of the requested group. | |
435 | // The size of TPM property group is PT_GROUP * 2 for fix and | |
436 | // variable groups. | |
437 | for(i = property; i <= PT_FIXED + PT_GROUP * 2; i++) | |
438 | { | |
439 | UINT32 value; | |
440 | if(TPMPropertyIsDefined((TPM_PT) i, &value)) | |
441 | { | |
442 | if(propertyList->count < count) | |
443 | { | |
444 | ||
445 | // If the list is not full, add this property | |
446 | propertyList->tpmProperty[propertyList->count].property = | |
447 | (TPM_PT) i; | |
448 | propertyList->tpmProperty[propertyList->count].value = value; | |
449 | propertyList->count++; | |
450 | } | |
451 | else | |
452 | { | |
453 | // If the return list is full but there are more properties | |
454 | // available, set the indication and exit the loop. | |
455 | more = YES; | |
456 | break; | |
457 | } | |
458 | } | |
459 | } | |
460 | return more; | |
461 | } |
#define TPM_FAIL_C
#include "InternalRoutines.h"
#include <assert.h>
On MS C compiler, can save the alignment state and set the alignment to 1 for the duration of the TPM_Types.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 TPM_Types.h and only include it for the #defines of the capabilities, properties, and command code values.
#pragma pack(push, 1)
#include "TPM_Types.h"
#pragma pack (pop)
#include "swap.h"
These defines are used primarily for sizing of the local response buffer.
#pragma pack(push,1)
typedef struct {
TPM_ST tag;
UINT32 size;
TPM_RC code;
} HEADER;
typedef struct {
UINT16 size;
struct {
UINT32 function;
UINT32 line;
UINT32 code;
} values;
TPM_RC returnCode;
} GET_TEST_RESULT_PARAMETERS;
typedef struct {
TPMI_YES_NO moreData;
TPM_CAP capability; // Always TPM_CAP_TPM_PROPERTIES
TPML_TAGGED_TPM_PROPERTY tpmProperty; // a single tagged property
} GET_CAPABILITY_PARAMETERS;
typedef struct {
HEADER header;
GET_TEST_RESULT_PARAMETERS getTestResult;
} TEST_RESPONSE;
typedef struct {
HEADER header;
GET_CAPABILITY_PARAMETERS getCap;
} CAPABILITY_RESPONSE;
typedef union {
TEST_RESPONSE test;
CAPABILITY_RESPONSE cap;
} RESPONSES;
#pragma pack(pop)
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.
#ifndef IGNORE_STATE // Don't define this value
static BYTE response[sizeof(RESPONSES)];
#endif
Function to marshal a 16 bit value to the output buffer.
static INT32
MarshalUint16(
UINT16 integer,
BYTE **buffer
48 )
49 {
50 return UINT16_Marshal(&integer, buffer, NULL); 51 }
Function to marshal a 32 bit value to the output buffer.
static INT32
MarshalUint32(
UINT32 integer,
BYTE **buffer
56 )
57 {
58 return UINT32_Marshal(&integer, buffer, NULL); 59 }
Funtion to unmarshal the 10-byte command header.
static BOOL
UnmarshalHeader(
HEADER *header,
BYTE **buffer,
INT32 *size
65 )
66 {
UINT32 usize;
TPM_RC ucode;
if( UINT16_Unmarshal(&header->tag, buffer, size) != TPM_RC_SUCCESS
|| UINT32_Unmarshal(&usize, buffer, size) != TPM_RC_SUCCESS
|| UINT32_Unmarshal(&ucode, buffer, size) != TPM_RC_SUCCESS 72 )
return FALSE;
header->size = usize;
header->code = ucode;
return TRUE; 77 }
This function is called by the simulator to enable failure mode testing.
LIB_EXPORT void
SetForceFailureMode(
void
81 )
82 {
g_forceFailureMode = TRUE;
return; 85 }
This function is called by TPM.lib when a failure occurs. It will set up the failure values to be returned on TPM2_GetTestResult().
void
TpmFail(
const char *function,
int line, int code 90 )
91 {
// Save the values that indicate where the error occurred.
// On a 64-bit machine, this may truncate the address of the string
// of the function name where the error occurred.
s_failFunction = *(UINT32*)&function;
s_failLine = line;
s_failCode = code; 98
// if asserts are enabled, then do an assert unless the failure mode code
// is being tested
assert(g_forceFailureMode); 102
// Clear this flag
g_forceFailureMode = FALSE; 105
// Jump to the failure mode code.
// Note: only get here if asserts are off or if we are testing failure mode
longjmp(&g_jumpBuffer[0], 1);
109 }
This function is called by the interface code when the platform is in failure mode.
void
TpmFailureMode (
unsigned int inRequestSize, // IN: command buffer size
unsigned char *inRequest, // IN: command buffer
unsigned int *outResponseSize, // OUT: response buffer size
unsigned char **outResponse // OUT: response buffer
116 )
117 {
BYTE *buffer;
UINT32 marshalSize;
UINT32 capability;
HEADER header; // unmarshaled command header
UINT32 pt; // unmarshaled property type
UINT32 count; // unmarshaled property count 124
// If there is no command buffer, then just return TPM_RC_FAILURE
if(inRequestSize == 0 || inRequest == NULL)
goto FailureModeReturn; 128
// If the header is not correct for TPM2_GetCapability() or
// TPM2_GetTestResult() then just return the in failure mode response;
buffer = inRequest;
if(!UnmarshalHeader(&header, &inRequest, (INT32 *)&inRequestSize))
goto FailureModeReturn;
if( header.tag != TPM_ST_NO_SESSIONS
|| header.size < 10)
goto FailureModeReturn; 137
switch (header.code) {
case TPM_CC_GetTestResult: 140
// make sure that the command size is correct
if(header.size != 10)
goto FailureModeReturn;
buffer = &response[10];
marshalSize = MarshalUint16(3 * sizeof(UINT32), &buffer);
marshalSize += MarshalUint32(s_failFunction, &buffer);
marshalSize += MarshalUint32(s_failLine, &buffer);
marshalSize += MarshalUint32(s_failCode, &buffer);
if(s_failCode == FATAL_ERROR_NV_UNRECOVERABLE)
marshalSize += MarshalUint32(TPM_RC_NV_UNINITIALIZED, &buffer);
else
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer);
break;
154
case TPM_CC_GetCapability:
// make sure that the size of the command is exactly the size
// returned for the capability, property, and count
if( header.size!= (10 + (3 * sizeof(UINT32)))
// also verify that this is requesting TPM properties
|| (UINT32_Unmarshal(&capability, &inRequest,
(INT32 *)&inRequestSize)
!= TPM_RC_SUCCESS)
|| (capability != TPM_CAP_TPM_PROPERTIES)
|| (UINT32_Unmarshal(&pt, &inRequest, (INT32 *)&inRequestSize)
!= TPM_RC_SUCCESS)
|| (UINT32_Unmarshal(&count, &inRequest, (INT32 *)&inRequestSize)
!= TPM_RC_SUCCESS)
168 )
169
170 goto FailureModeReturn; 171
// If in failure mode because of an unrecoverable read error, and the
// property is 0 and the count is 0, then this is an indication to
// re-manufacture the TPM. Do the re-manufacture but stay in failure
// mode until the TPM is reset.
// Note: this behavior is not required by the specification and it is
// OK to leave the TPM permanently bricked due to an unrecoverable NV
// error.
if( count == 0 && pt == 0 && s_failCode == FATAL_ERROR_NV_UNRECOVERABLE)
180 {
g_manufactured = FALSE;
TPM_Manufacture(0);
183 }
184
if(count > 0)
count = 1;
else if(pt > TPM_PT_FIRMWARE_VERSION_2)
count = 0;
if(pt < TPM_PT_MANUFACTURER)
pt = TPM_PT_MANUFACTURER; 191
// set up for return
buffer = &response[10];
// if the request was for a PT less than the last one
// then we indicate more, otherwise, not.
if(pt < TPM_PT_FIRMWARE_VERSION_2)
*buffer++ = YES;
else
*buffer++ = NO; 200
201 marshalSize = 1; 202
// indicate the capability type
marshalSize += MarshalUint32(capability, &buffer);
// indicate the number of values that are being returned (0 or 1)
marshalSize += MarshalUint32(count, &buffer);
// indicate the property
marshalSize += MarshalUint32(pt, &buffer); 209
if(count > 0)
switch (pt) {
case TPM_PT_MANUFACTURER:
// the vendor ID unique to each TPM manufacturer
#ifdef MANUFACTURER
pt = *(UINT32*)MANUFACTURER;
#else
217 pt = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_1:
// the first four characters of the vendor ID string
#ifdef VENDOR_STRING_1
pt = *(UINT32*)VENDOR_STRING_1;
#else
225 pt = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_2:
// the second four characters of the vendor ID string
#ifdef VENDOR_STRING_2
pt = *(UINT32*)VENDOR_STRING_2;
#else
233 pt = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_3:
// the third four characters of the vendor ID string
#ifdef VENDOR_STRING_3
pt = *(UINT32*)VENDOR_STRING_3;
#else
241 pt = 0;
#endif
break;
case TPM_PT_VENDOR_STRING_4:
// the fourth four characters of the vendor ID string
#ifdef VENDOR_STRING_4
pt = *(UINT32*)VENDOR_STRING_4;
#else
249 pt = 0;
250 #endif 251
break;
case TPM_PT_VENDOR_TPM_TYPE:
// vendor-defined value indicating the TPM model
// We just make up a number here
256 pt = 1;
break;
case TPM_PT_FIRMWARE_VERSION_1:
// the more significant 32-bits of a vendor-specific value
// indicating the version of the firmware
#ifdef FIRMWARE_V1
pt = FIRMWARE_V1;
#else
264 pt = 0;
#endif
break;
default: // TPM_PT_FIRMWARE_VERSION_2:
// the less significant 32-bits of a vendor-specific value
// indicating the version of the firmware
#ifdef FIRMWARE_V2
pt = FIRMWARE_V2;
#else
273 pt = 0;
#endif
break;
276 }
marshalSize += MarshalUint32(pt, &buffer);
break;
default: // default for switch (cc)
goto FailureModeReturn;
281 }
// Now do the header
buffer = response;
marshalSize = marshalSize + 10; // Add the header size to the
// stuff already marshaled
MarshalUint16(TPM_ST_NO_SESSIONS, &buffer); // structure tag
MarshalUint32(marshalSize, &buffer); // responseSize
MarshalUint32(TPM_RC_SUCCESS, &buffer); // response code 289
*outResponseSize = marshalSize;
*outResponse = (unsigned char *)&response;
return; 293
294 FailureModeReturn: 295
296 buffer = response; 297
marshalSize = MarshalUint16(TPM_ST_NO_SESSIONS, &buffer);
marshalSize += MarshalUint32(10, &buffer);
marshalSize += MarshalUint32(TPM_RC_FAILURE, &buffer); 301
*outResponseSize = marshalSize;
*outResponse = (unsigned char *)response;
return;
305 }
The files in this section provide cryptographic support for the other functions in the TPM and the interface to the Crypto Engine.
#include "TPM_Types.h"
#include "CryptoEngine.h" // types shared by CryptUtil and CryptoEngine.
// Includes the function prototypes for the
// CryptoEngine functions.
#include "Global.h"
#include "InternalRoutines.h"
#include "MemoryLib_fp.h"
//#include "CryptSelfTest_fp.h"
This function converts errors from the cryptographic library into TPM_RC_VALUES.
Error Returns | Meaning |
TPM_RC_VALUE | CRYPT_FAIL |
TPM_RC_NO_RESULT | CRYPT_NO_RESULT |
TPM_RC_SCHEME | CRYPT_SCHEME |
TPM_RC_VALUE | CRYPT_PARAMETER |
TPM_RC_SIZE | CRYPT_UNDERFLOW |
TPM_RC_ECC_POINT | CRYPT_POINT |
TPM_RC_CANCELLED | CRYPT_CANCEL |
static TPM_RC
TranslateCryptErrors (
CRYPT_RESULT retVal // IN: crypt error to evaluate 12 )
13 {
14 switch (retVal)
15 {
case CRYPT_SUCCESS:
return TPM_RC_SUCCESS;
case CRYPT_FAIL:
return TPM_RC_VALUE;
case CRYPT_NO_RESULT:
return TPM_RC_NO_RESULT;
case CRYPT_SCHEME:
return TPM_RC_SCHEME;
case CRYPT_PARAMETER:
return TPM_RC_VALUE;
case CRYPT_UNDERFLOW:
return TPM_RC_SIZE;
case CRYPT_POINT:
return TPM_RC_ECC_POINT;
case CRYPT_CANCEL:
return TPM_RC_CANCELED;
default: // Other unknown warnings
return TPM_RC_FAILURE; 34 }
35 }
#ifdef TPM_ALG_NULL //%
#ifdef _DRBG_STATE_SAVE //%
Read or write the current state from the DRBG in the cryptoEngine.
void
CryptDrbgGetPutState(
GET_PUT direction // IN: Get from or put to DRBG 41 )
42 {
_cpri DrbgGetPutState(direction,
sizeof(go.drbgState),
(BYTE *)&go.drbgState);
46 }
47 #else //% 00
//%#define CryptDrbgGetPutState(ignored) // If not doing state save, turn this
//% // into a null macro
#endif //%
Stir random entropy
void
CryptStirRandom(
UINT32 entropySize, // IN: size of entropy buffer
BYTE *buffer // IN: entropy buffer 55 )
56 {
57 // RNG self testing code may be inserted here 58
// Call crypto engine random number stirring function
_cpri StirRandom(entropySize, buffer); 61
62 return; 63 }
This is the interface to _cpri GenerateRandom().
UINT16
CryptGenerateRandom(
UINT16 randomSize, // IN: size of random number
BYTE *buffer // OUT: buffer of random number 68 )
69 {
UINT16 result;
pAssert(randomSize <= MAX_RSA_KEY_BYTES || randomSize <= PRIMARY_SEED_SIZE);
if(randomSize == 0)
return 0;
74
// Call crypto engine random number generation
result = _cpri GenerateRandom(randomSize, buffer);
if(result != randomSize)
FAIL(FATAL_ERROR_INTERNAL); 79
80 return result; 81 }
#endif //TPM_ALG_NULL //%
This function returns the hash algorithm associated with a hash context.
#ifdef TPM_ALG_KEYEDHASH //% 1
TPM_ALG_ID
CryptGetContextAlg(
void *state // IN: the context to check 87 )
88 {
HASH_STATE *context = (HASH_STATE *)state;
return _cpri GetContextAlg(&context->state); 91 }
This function starts a hash and return the size, in bytes, of the digest.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
UINT16
CryptStartHash(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
HASH_STATE *hashState // OUT: the state of hash stack. It will be used
// in hash update and completion
97 )
98 {
99 CRYPT_RESULT retVal = 0; 100
101 pAssert(hashState != NULL); 102
103 TEST_HASH(hashAlg); 104
105 hashState->type = HASH_STATE_EMPTY; 106
// Call crypto engine start hash function
if((retVal = _cpri StartHash(hashAlg, FALSE, &hashState->state)) > 0)
hashState->type = HASH_STATE_HASH; 110
111 return retVal;
112 }
Start a hash stack for a sequence object and return the size, in bytes, of the digest. This call uses the form of the hash state that requires context save and restored.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
UINT16
CryptStartHashSequence(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
HASH_STATE *hashState // OUT: the state of hash stack. It will be used
// in hash update and completion
118 )
119 {
120 CRYPT_RESULT retVal = 0; 121
122 pAssert(hashState != NULL); 123
124 TEST_HASH(hashAlg); 125
126 hashState->type = HASH_STATE_EMPTY; 127
// Call crypto engine start hash function
if((retVal = _cpri StartHash(hashAlg, TRUE, &hashState->state)) > 0)
hashState->type = HASH_STATE_HASH; 131
132 return retVal; 133
134 }
This function starts an HMAC sequence and returns the size of the digest that will be produced.
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.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
UINT16
CryptStartHMAC(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
UINT16 keySize, // IN: the size of HMAC key in byte
BYTE *key, // IN: HMAC key
HMAC_STATE *hmacState // OUT: the state of HMAC stack. It will be used
// in HMAC update and completion
142 )
143 {
HASH_STATE *hashState = (HASH_STATE *)hmacState;
CRYPT_RESULT retVal; 146
// This has to come before the pAssert in case we all calling this function
// during testing. If so, the first instance will have no arguments but the
// hash algorithm. The call from the test routine will have arguments. When
// the second call is done, then we return to the test dispatcher.
TEST_HASH(hashAlg);
152 | ||
153 | pAssert(hashState != NULL); | |
154 | ||
155 | hashState->type = HASH_STATE_EMPTY; | |
156 | ||
157 | if((retVal = _cpri StartHMAC(hashAlg, FALSE, &hashState->state, keySize, key, | |
158 | &hmacState->hmacKey.b)) > 0) | |
159 | hashState->type = HASH_STATE_HMAC; | |
160 | ||
161 | return retVal; | |
162 | } |
This function starts an HMAC sequence and returns the size of the digest that will be produced.
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.
This call is used to start a sequence HMAC that spans multiple TPM commands.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
UINT16
CryptStartHMACSequence(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
UINT16 keySize, // IN: the size of HMAC key in byte
BYTE *key, // IN: HMAC key
HMAC_STATE *hmacState // OUT: the state of HMAC stack. It will be used
// in HMAC update and completion
170 )
171 {
HASH_STATE *hashState = (HASH_STATE *)hmacState;
CRYPT_RESULT retVal; 174
175 TEST_HASH(hashAlg); 176
177 hashState->type = HASH_STATE_EMPTY; 178
if((retVal = _cpri StartHMAC(hashAlg, TRUE, &hashState->state,
keySize, key, &hmacState->hmacKey.b)) > 0)
hashState->type = HASH_STATE_HMAC; 182
183 return retVal;
184 }
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.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
185 | LIB_EXPORT UINT16 | |
186 | CryptStartHMAC2B( | |
187 | TPMI_ALG_HASH hashAlg, | // IN: hash algorithm |
188 | TPM2B *key, | // IN: HMAC key |
189 | HMAC_STATE *hmacState | // OUT: the state of HMAC stack. It will be used |
190 | // in HMAC update and completion | |
191 | ) | |
192 | { | |
193 | return CryptStartHMAC(hashAlg, | key->size, key->buffer, hmacState); |
194 | } |
This function starts an HMAC sequence 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.
Return Value | Meaning |
> 0 | the digest size of the algorithm |
= 0 | the hashAlg was TPM_ALG_NULL |
UINT16
CryptStartHMACSequence2B(
TPMI_ALG_HASH hashAlg, // IN: hash algorithm
TPM2B *key, // IN: HMAC key
HMAC_STATE *hmacState // OUT: the state of HMAC stack. It will be used
// in HMAC update and completion
201 )
202 {
203 return CryptStartHMACSequence(hashAlg, key->size, key->buffer, hmacState);
204 }
This function updates a digest (hash or HMAC) with an array of octets.
This function can be used for both HMAC and hash functions so the digestState is void so that either state type can be passed.
LIB_EXPORT void
CryptUpdateDigest(
void *digestState, // IN: the state of hash stack
UINT32 dataSize, // IN: the size of data
BYTE *data // IN: data to be hashed
210 )
211 {
212 HASH_STATE *hashState = (HASH_STATE *)digestState; 213
214 pAssert(digestState != NULL); 215
216 if(hashState->type != HASH_STATE_EMPTY && data != NULL && dataSize != 0)
217 {
// Call crypto engine update hash function
_cpri UpdateHash(&hashState->state, dataSize, data);
220 }
221 return;
222 }
This function updates a digest (hash or HMAC) with a TPM2B.
This function can be used for both HMAC and hash functions so the digestState is void so that either state type can be passed.
LIB_EXPORT void
CryptUpdateDigest2B(
void *digestState, // IN: the digest state
TPM2B *bIn // IN: 2B containing the data
227 )
228 {
// Only compute the digest if a pointer to the 2B is provided.
// In CryptUpdateDigest(), if size is zero or buffer is NULL, then no change
// to the digest occurs. This function should not provide a buffer if bIn is
// not provided.
if(bIn != NULL)
CryptUpdateDigest(digestState, bIn->size, bIn->buffer);
return;
236 }
This function is used to include an integer value to a hash stack. The function marshals the integer into its canonical form before calling CryptUpdateHash().
LIB_EXPORT void
CryptUpdateDigestInt(
void *state, // IN: the state of hash stack
UINT32 intSize, // IN: the size of 'intValue' in byte
void *intValue // IN: integer value to be hashed
242 )
243 { 244
#if BIG_ENDIAN_TPM == YES
pAssert( intValue != NULL && (intSize == 1 || intSize == 2
|| intSize == 4 || intSize == 8));
CryptUpdateHash(state, inSize, (BYTE *)intValue);
#else 250
BYTE marshalBuffer[8];
// Point to the big end of an little-endian value
BYTE *p = &((BYTE *)intValue)[intSize - 1];
// Point to the big end of an big-endian value
BYTE *q = marshalBuffer; 256
pAssert(intValue != NULL);
switch (intSize)
259 {
260 case 8:
261 *q++ = *p--;
262 *q++ = *p--;
263 *q++ = *p--;
264 *q++ = *p--;
265 case 4:
266 *q++ = *p--;
267 *q++ = *p--;
268 case 2:
269 *q++ = *p--;
270 case 1:
271 *q = *p;
// Call update the hash
CryptUpdateDigest(state, intSize, marshalBuffer);
break;
default:
FAIL(0);
277 }
278
#endif
return;
281 }
This function completes a hash sequence and returns the digest.
This function can be called to complete either an HMAC or hash sequence. The state type determines if the context type is a hash or HMAC. If an HMAC, then the call is forwarded to CryptCompleteHash().
If digestSize is smaller than the digest size of hash/HMAC algorithm, the most significant bytes of required size will be returned
Return Value | Meaning |
>=0 | the number of bytes placed in digest |
LIB_EXPORT UINT16
CryptCompleteHash(
void *state, // IN: the state of hash stack
UINT16 digestSize, // IN: size of digest buffer
BYTE *digest // OUT: hash digest
287 )
288 {
289 HASH_STATE *hashState = (HASH_STATE *)state; // local value 290
// If the session type is HMAC, then could forward this to
// the HMAC processing and not cause an error. However, if no
// function calls this routine to forward it, then we can't get
// test coverage. The decision is to assert if this is called with
// the type == HMAC and fix anything that makes the wrong call.
pAssert(hashState->type == HASH_STATE_HASH); 297
// Set the state to empty so that it doesn't get used again
hashState->type = HASH_STATE_EMPTY; 300
// Call crypto engine complete hash function
return _cpri CompleteHash(&hashState->state, digestSize, digest);
303 }
This function is the same as CypteCompleteHash() 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
Return Value | Meaning |
>=0 | the number of bytes placed in 'digest.buffer' |
LIB_EXPORT UINT16
CryptCompleteHash2B(
void *state, // IN: the state of hash stack
TPM2B *digest // IN: the size of the buffer Out: requested
// number of byte
309 )
310 {
311 UINT16 retVal = 0; 312
if(digest != NULL)
retVal = CryptCompleteHash(state, digest->size, digest->buffer); 315
316 return retVal;
317 }
Hash a block of data and return the results. If the digest is larger than retSize, it is truncated and with the least significant octets dropped.
Return Value | Meaning |
>=0 | the number of bytes placed in ret |
318 | LIB_EXPORT UINT16 | |
319 | CryptHashBlock( | |
320 | TPM_ALG_ID algId, | // IN: the hash algorithm to use |
321 | UINT16 blockSize, | // IN: size of the data block |
322 | BYTE *block, | // IN: address of the block to hash |
323 | UINT16 retSize, | // IN: size of the return buffer |
324 | BYTE *ret | // OUT: address of the buffer |
325 | ) | |
326 | { | |
327 | TEST_HASH(algId); | |
328 | ||
329 | return _cpri HashBlock(algId, | blockSize, block, retSize, ret); |
330 | } |
This function completes a HMAC sequence and returns the digest. If digestSize is smaller than the digest size of the HMAC algorithm, the most significant bytes of required size will be returned.
Return Value | Meaning |
>=0 | the number of bytes placed in digest |
331 | LIB_EXPORT UINT16 | |||
332 | CryptCompleteHMAC( | |||
333 | HMAC_STATE | *hmacState, | // | IN: the state of HMAC stack |
334 | UINT32 | digestSize, | // | IN: size of digest buffer |
335 | BYTE | *digest | // | OUT: HMAC digest |
336 | ) | |||
337 | { | |||
338 | HASH_STATE | *hashState; | ||
339 |
pAssert(hmacState != NULL);
hashState = &hmacState->hashState; 342
343 pAssert(hashState->type == HASH_STATE_HMAC); 344
345 hashState->type = HASH_STATE_EMPTY; 346
return _cpri CompleteHMAC(&hashState->state, &hmacState->hmacKey.b,
digestSize, digest);
349
350 }
This function is the same as CryptCompleteHMAC() but the HMAC result is returned in a TPM2B which is the most common use.
Return Value | Meaning |
>=0 | the number of bytes placed in digest |
LIB_EXPORT UINT16
CryptCompleteHMAC2B(
HMAC_STATE *hmacState, // IN: the state of HMAC stack
TPM2B *digest // OUT: HMAC
355 )
356 {
UINT16 retVal = 0;
if(digest != NULL)
retVal = CryptCompleteHMAC(hmacState, digest->size, digest->buffer);
return retVal;
361 }
This function is used to prepare a hash state context for LIB_EXPORT or to import it into the internal format. It is used by TPM2_ContextSave() and TPM2_ContextLoad() via SequenceDataImportExport(). This is just a pass-through function to the crypto library.
void
CryptHashStateImportExport(
HASH_STATE *internalFmt, // IN: state to LIB_EXPORT
HASH_STATE *externalFmt, // OUT: exported state
IMPORT_EXPORT direction
367 )
368 {
369 _cpri ImportExportHashState(&internalFmt->state,
370 | (EXPORT_HASH_STATE *)&externalFmt->state, | |
371 | direction); | |
372 | } |
This function returns the digest size in bytes for a hash algorithm.
Return Value | Meaning |
0 | digest size for TPM_ALG_NULL |
> 0 | digest size |
LIB_EXPORT UINT16
CryptGetHashDigestSize(
TPM_ALG_ID hashAlg // IN: hash algorithm
376 )
377 {
378 return _cpri GetDigestSize(hashAlg);
379 }
Get the digest size in byte of a hash algorithm.
Return Value | Meaning |
0 | block size for TPM_ALG_NULL |
> 0 | block size |
LIB_EXPORT UINT16
CryptGetHashBlockSize(
TPM_ALG_ID hash // IN: hash algorithm to look up
383 )
384 {
385 return _cpri GetHashBlockSize(hash);
386 }
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 value of 2 will return the last implemented hash. All other index values will return TPM_ALG_NULL.
Return Value | Meaning |
TPM_ALG_xxx() | a hash algorithm |
TPM_ALG_NULL | this can be used as a stop value |
LIB_EXPORT TPM_ALG_ID
CryptGetHashAlgByIndex(
UINT32 index // IN: the index
390 )
391 {
392 return _cpri GetHashAlgByIndex(index);
393 }
Sign a digest using an HMAC key. This an HMAC of a digest, not an HMAC of a message.
Error Returns | Meaning |
static TPM_RC
CryptSignHMAC(
OBJECT *signKey, // IN: HMAC key sign the hash
TPMT_SIG_SCHEME *scheme, // IN: signing scheme
TPM2B_DIGEST *hashData, // IN: hash to be signed
TPMT_SIGNATURE *signature // OUT: signature
400 )
401 {
402 | HMAC_STATE hmacState; | |
403 | UINT32 digestSize; | |
404 | ||
405 | // HMAC algorithm self testing code may be inserted here | |
406 | ||
407 | digestSize = CryptStartHMAC2B(scheme->details.hmac.hashAlg, | |
408 | &signKey->sensitive.sensitive.bits.b, | |
409 | &hmacState); | |
410 | ||
411 | // The hash algorithm must be a valid one. | |
412 | pAssert(digestSize > 0); | |
413 | ||
414 | CryptUpdateDigest2B(&hmacState, &hashData->b); | |
415 | ||
416 | CryptCompleteHMAC(&hmacState, digestSize, | |
417 | (BYTE *) &signature->signature.hmac.digest); | |
418 | ||
419 | // Set HMAC algorithm | |
420 | signature->signature.hmac.hashAlg = scheme->details.hmac.hashAlg; | |
421 | ||
422 | return TPM_RC_SUCCESS; | |
423 | } |
This function will verify a signature signed by a HMAC key.
Error Returns | Meaning |
TPM_RC_SIGNATURE | if invalid input or signature is not genuine |
424 static TPM_RC
425 CryptHMACVerifySignature(
426 OBJECT *signKey, // IN: HMAC key signed the hash
427 TPM2B_DIGEST *hashData, // IN: digest being verified
428 TPMT_SIGNATURE *signature // IN: signature to be verified
429 )
430 {
431 HMAC_STATE hmacState;
432 TPM2B_DIGEST digestToCompare; 433
434 digestToCompare.t.size = CryptStartHMAC2B(signature->signature.hmac.hashAlg,
435 &signKey->sensitive.sensitive.bits.b, &hmacState); 436
437 CryptUpdateDigest2B(&hmacState, &hashData->b); 438
439 CryptCompleteHMAC2B(&hmacState, &digestToCompare.b); 440
// Compare digest
if(MemoryEqual(digestToCompare.t.buffer,
(BYTE *) &signature->signature.hmac.digest,
digestToCompare.t.size))
return TPM_RC_SUCCESS;
else
return TPM_RC_SIGNATURE; 448
449 }
This function creates a keyedHash object.
Error Returns | Meaning |
TPM_RC_SIZE | sensitive data size is larger than allowed for the scheme |
static TPM_RC
CryptGenerateKeyedHash(
TPMT_PUBLIC *publicArea, // IN/OUT: the public area template
// for the new key.
TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation data
TPMT_SENSITIVE *sensitive, // OUT: sensitive area
TPM_ALG_ID kdfHashAlg, // IN: algorithm for the KDF
TPM2B_SEED *seed, // IN: the seed
TPM2B_NAME *name // IN: name of the object
459 )
460 {
461 TPMT_KEYEDHASH_SCHEME *scheme;
462 TPM_ALG_ID hashAlg;
463 UINT16 hashBlockSize; 464
465 scheme = &publicArea->parameters.keyedHashDetail.scheme; 466
467 pAssert(publicArea->type == TPM_ALG_KEYEDHASH); 468
// Pick the limiting hash algorithm
if(scheme->scheme == TPM_ALG_NULL)
hashAlg = publicArea->nameAlg;
else if(scheme->scheme == TPM_ALG_XOR)
hashAlg = scheme->details.xor.hashAlg;
else
hashAlg = scheme->details.hmac.hashAlg;
hashBlockSize = CryptGetHashBlockSize(hashAlg); 477
478 // if this is a signing or a decryption key, then then the limit
479 // for the data size is the block size of the hash. This limit
480 // is set because larger values have lower entropy because of the
481 // HMAC function.
482 if(publicArea->objectAttributes.sensitiveDataOrigin == CLEAR)
483 {
484 if( ( publicArea->objectAttributes.decrypt
485 || publicArea->objectAttributes.sign)
486 && sensitiveCreate->data.t.size > hashBlockSize) 487
488 return TPM_RC_SIZE;
489 }
490 else
491 {
492 // If the TPM is going to generate the data, then set the size to be the
493 // size of the digest of the algorithm
494 sensitive->sensitive.sym.t.size = CryptGetHashDigestSize(hashAlg);
495 sensitiveCreate->data.t.size = 0;
496 }
497
498 // Fill in the sensitive area
499 CryptGenerateNewSymmetric(sensitiveCreate, sensitive, kdfHashAlg,
500 seed, name);
501
502 // Create unique area in public
503 CryptComputeSymmetricUnique(publicArea->nameAlg,
504 sensitive, &publicArea->unique.sym); 505
506 return TPM_RC_SUCCESS;
507 }
This function generates a key using the KDFa() formulation in Part 1 of the TPM specification. In this implementation, this is a macro invocation of _cpri__KDFa() in the hash module of the CryptoEngine(). This macro sets once to FALSE so that KDFa() will iterate as many times as necessary to generate sizeInBits number of bits.
508 | //%#define | CryptKDFa(hashAlg, key, label, contextU, contextV, | \ |
509 | //% | sizeInBits, keyStream, counterInOut) | \ |
510 | //% | TEST_HASH(hashAlg); | \ |
511 | //% | _cpri KDFa( | \ |
512 | //% | ((TPM_ALG_ID)hashAlg), | \ |
513 | //% | ((TPM2B *)key), | \ |
514 | //% | ((const char *)label), | \ |
515 | //% | ((TPM2B *)contextU), | \ |
516 | //% | ((TPM2B *)contextV), | \ |
517 | //% | ((UINT32)sizeInBits), | \ |
518 | //% | ((BYTE *)keyStream), | \ |
519 | //% | ((UINT32 *)counterInOut), | \ |
520 | //% | ((BOOL) FALSE) | \ |
521 | //% | ) | |
522 | //% |
This function generates a key using the KDFa() formulation in Part 1 of the TPM specification. In this implementation, this is a macro invocation of _cpri__KDFa() in the hash module of the CryptoEngine(). This macro will call _cpri__KDFa() with once TRUE so that only one iteration is performed, regardless of sizeInBits.
523 | //%#define | CryptKDFaOnce(hashAlg, key, label, contextU, contextV, | \ |
524 | //% | sizeInBits, keyStream, counterInOut) | \ |
525 | //% | TEST_HASH(hashAlg); | \ |
526 | //% | _cpri KDFa( | \ |
527 | //% | ((TPM_ALG_ID)hashAlg), | \ |
528 | //% | ((TPM2B *)key), | \ |
529 | //% | ((const char *)label), | \ |
530 | //% | ((TPM2B *)contextU), | \ |
531 | //% | ((TPM2B *)contextV), | \ |
532 | //% | ((UINT32)sizeInBits), | \ |
533 | //% | ((BYTE *)keyStream), | \ |
534 | //% | ((UINT32 *)counterInOut), | \ |
535 | //% | ((BOOL) TRUE) | \ |
536 | //% | ) | |
537 | //% |
This function is used by functions outside of CryptUtil() to access _cpri_KDFa(). | |
538 | void |
539 | KDFa( |
540 | TPM_ALG_ID hash, // IN: hash algorithm used in HMAC |
541 | TPM2B *key, // IN: HMAC key |
542 | const char *label, // IN: a null-terminated label for KDF |
543 | TPM2B *contextU, // IN: context U |
544 | TPM2B *contextV, // IN: context V |
545 | UINT32 sizeInBits, // IN: size of generated key in bit |
546 | BYTE *keyStream, // OUT: key buffer |
547 | UINT32 *counterInOut // IN/OUT: caller may provide the iteration |
548 | // counter for incremental operations to |
549 | // avoid large intermediate buffers. | |
550 | ) | |
551 | { | |
552 | CryptKDFa(hash, key, label, contextU, contextV, sizeInBits, | |
553 | keyStream, counterInOut); | |
554 | } |
This function generates a key using the KDFa() formulation in Part 1 of the TPM specification. In this implementation, this is a macro invocation of _cpri__KDFe() in the hash module of the CryptoEngine().
555 | //%#define CryptKDFe(hashAlg, Z, label, partyUInfo, partyVInfo, \ | |
556 | //% sizeInBits, keyStream) \ | |
557 | //% TEST_HASH(hashAlg); \ | |
558 | //% _cpri KDFe( \ | |
559 | //% ((TPM_ALG_ID)hashAlg), \ | |
560 | //% ((TPM2B *)Z), \ | |
561 | //% ((const char *)label), \ | |
562 | //% ((TPM2B *)partyUInfo), \ | |
563 | //% ((TPM2B *)partyVInfo), \ | |
564 | //% ((UINT32)sizeInBits), \ | |
565 | //% ((BYTE *)keyStream) \ | |
566 | //% ) | |
567 | //% | |
568 | #endif //TPM_ALG_KEYEDHASH //% 1 | |
Function to set the cryptographic elements of an RSA key into a structure to simplify | the interface to |
_cpri__ RSA function. This can/should be eliminated by building this structure into the object structure.
569 #ifdef TPM_ALG_RSA //% 2
570 static void
571 BuildRSA(
572 OBJECT *rsaKey,
573 RSA_KEY *key
574 )
575 {
576 key->exponent = rsaKey->publicArea.parameters.rsaDetail.exponent;
577 if(key->exponent == 0)
578 key->exponent = RSA_DEFAULT_PUBLIC_EXPONENT;
579 key->publicKey = &rsaKey->publicArea.unique.rsa.b; 580
581 if(rsaKey->attributes.publicOnly || rsaKey->privateExponent.t.size == 0)
582 key->privateKey = NULL;
583 else
584 key->privateKey = &(rsaKey->privateExponent.b);
585 }
This function provides the interface to _cpri__TestKeyRSA(). If both p and q are provided, n will be set to
p*q.
If only p is provided, q is computed by q = n/p. If n mod p != 0, TPM_RC_BINDING is returned.
The key is validated by checking that a d can be found such that e d mod ((p-1)*(q-1)) = 1. If d is found that satisfies this requirement, it will be placed in d.
Error Returns | Meaning |
TPM_RC_BINDING | the public and private portions of the key are not matched |
586 | TPM_RC | ||||
587 | CryptTestKeyRSA( | ||||
588 | TPM2B | *d, | // | OUT: receives the private exponent | |
589 | UINT32 | e, | // | IN: public exponent | |
590 | TPM2B | *n, | // | IN/OUT: public modulu | |
591 | TPM2B | *p, | // | IN: a first prime | |
592 | TPM2B | *q | // | IN: an optional second prime | |
593 | ) | ||||
594 | { | ||||
595 | CRYPT_RESULT | retVal; | |||
596 | |||||
597 | TEST(ALG_NULL_VALUE); | ||||
598 | |||||
599 | pAssert(d != NULL && n != NULL && p != | NULL); | |||
600 | // Set the exponent | ||||
601 | if(e == 0) | ||||
602 | e = RSA_DEFAULT_PUBLIC_EXPONENT; | ||||
603 | // CRYPT_PARAMETER | ||||
604 | retVal =_cpri TestKeyRSA(d, e, n, p, q); | ||||
605 | if(retVal == CRYPT_SUCCESS) | ||||
606 | return TPM_RC_SUCCESS; | ||||
607 | else | ||||
608 | return TPM_RC_BINDING; // convert CRYPT_PARAMETER | ||||
609 | } |
This function is called to generate an RSA key from a provided seed. It calls _cpri__GenerateKeyRSA() to perform the computations. The implementation is vendor specific.
Error Returns | Meaning |
TPM_RC_RANGE | the exponent value is not supported |
TPM_RC_CANCELLED | key generation has been canceled |
TPM_RC_VALUE | exponent is not prime or is less than 3; or could not find a prime using the provided parameters |
610 static TPM_RC
611 CryptGenerateKeyRSA(
612 TPMT_PUBLIC *publicArea, // IN/OUT: The public area template for 613 // the new key. The public key
614 // area will be replaced by the
615 // product of two primes found by
616 // this function
617 TPMT_SENSITIVE *sensitive, // OUT: the sensitive area will be 618 // updated to contain the first
619 // prime and the symmetric
620 // encryption key
621 TPM_ALG_ID hashAlg, // IN: the hash algorithm for the KDF 622 TPM2B_SEED *seed, // IN: Seed for the creation
623 TPM2B_NAME *name, // IN: Object name
624 UINT32 *counter // OUT: last iteration of the counter 625 )
626 {
627 CRYPT_RESULT retVal;
628 UINT32 exponent = publicArea->parameters.rsaDetail.exponent; 629
630 TEST_HASH(hashAlg);
631 | TEST(ALG_NULL_VALUE); | |
632 | ||
633 | // In this implementation, only the default exponent is allowed | |
634 | if(exponent != 0 && exponent != RSA_DEFAULT_PUBLIC_EXPONENT) | |
635 | return TPM_RC_RANGE; | |
636 | exponent = RSA_DEFAULT_PUBLIC_EXPONENT; | |
637 | ||
638 | *counter = 0; | |
639 | ||
640 | // _cpri_GenerateKeyRSA can return CRYPT_CANCEL or CRYPT_FAIL | |
641 | retVal = _cpri GenerateKeyRSA(&publicArea->unique.rsa.b, | |
642 | &sensitive->sensitive.rsa.b, | |
643 | publicArea->parameters.rsaDetail.keyBits, | |
644 | exponent, | |
645 | hashAlg, | |
646 | &seed->b, | |
647 | "RSA key by vendor", | |
648 | &name->b, | |
649 | counter); | |
650 | ||
651 | // CRYPT_CANCEL -> TPM_RC_CANCELLED; CRYPT_FAIL -> TPM_RC_VALUE | |
652 | return TranslateCryptErrors(retVal); | |
653 | ||
654 | } |
This function is called to generate the private exponent of an RSA key. It uses CryptTestKeyRSA().
Error Returns | Meaning |
TPM_RC_BINDING | public and private parts of rsaKey are not matched |
655 | TPM_RC | |
656 | CryptLoadPrivateRSA( | |
657 | OBJECT *rsaKey | // IN: the RSA key object |
658 | ) | |
659 | { | |
660 | TPM_RC result; | |
661 | TPMT_PUBLIC *publicArea = &rsaKey->publicArea; | |
662 | TPMT_SENSITIVE *sensitive = &rsaKey->sensitive; | |
663 | ||
664 | // Load key by computing the private exponent | |
665 | // TPM_RC_BINDING | |
666 | result = CryptTestKeyRSA(&(rsaKey->privateExponent.b), | |
667 | publicArea->parameters.rsaDetail.exponent, | |
668 | &(publicArea->unique.rsa.b), | |
669 | &(sensitive->sensitive.rsa.b), | |
670 | NULL); | |
671 | if(result == TPM_RC_SUCCESS) | |
672 | rsaKey->attributes.privateExp = SET; | |
673 | ||
674 | return result; | |
675 | } |
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.
676 TPMT_RSA_DECRYPT*
677 CryptSelectRSAScheme(
678 TPMI_DH_OBJECT rsaHandle, // IN: handle of sign key
679 TPMT_RSA_DECRYPT *scheme // IN: a sign or decrypt scheme 680 )
681 {
682 OBJECT *rsaObject;
683 TPMT_ASYM_SCHEME *keyScheme;
684 TPMT_RSA_DECRYPT *retVal = NULL;
685
686 // Get sign object pointer
687 rsaObject = ObjectGet(rsaHandle);
688 keyScheme = &rsaObject->publicArea.parameters.asymDetail.scheme; 689
690 // if the default scheme of the object is TPM_ALG_NULL, then select the 691 // input scheme
692 if(keyScheme->scheme == TPM_ALG_NULL) 693 {
694 retVal = scheme; 695 }
696 // if the object scheme is not TPM_ALG_NULL and the input scheme is 697 // TPM_ALG_NULL, then select the default scheme of the object.
698 else if(scheme->scheme == TPM_ALG_NULL) 699 {
700 // if input scheme is NULL
701 retVal = (TPMT_RSA_DECRYPT *)keyScheme; 702 }
703 // get here if both the object scheme and the input scheme are 704 // not TPM_ALG_NULL. Need to insure that they are the same.
705 // IMPLEMENTATION NOTE: This could cause problems if future versions have 706 // schemes that have more values than just a hash algorithm. A new function 707 // (IsSchemeSame()) might be needed then.
708 else if( keyScheme->scheme == scheme->scheme
709 && keyScheme->details.anySig.hashAlg == scheme->details.anySig.hashAlg) 710 {
711 retVal = scheme; 712 }
713 // two different, incompatible schemes specified will return NULL 714 return retVal;
715 }
This function is the interface to _cpri__DecryptRSA(). It handles the return codes from that function and converts them from CRYPT_RESULT to TPM_RC values. The rsaKey parameter must reference an RSA decryption key
Error Returns | Meaning |
TPM_RC_BINDING | Public and private parts of the key are not cryptographically bound. |
TPM_RC_SIZE | Size of data to decrypt is not the same as the key size. |
TPM_RC_VALUE | Numeric value of the encrypted data is greater than the public exponent, or output buffer is too small for the decrypted message. |
716 | TPM_RC | ||
717 | CryptDecryptRSA( | ||
718 | UINT16 | *dataOutSize, | // OUT: size of plain text in byte |
719 | BYTE *dataOut, // OUT: plain text | |
720 | OBJECT *rsaKey, // IN: internal RSA key | |
721 | TPMT_RSA_DECRYPT *scheme, // IN: selects the padding scheme | |
722 | UINT16 cipherInSize, // IN: size of cipher text in byte | |
723 | BYTE *cipherIn, // IN: cipher text | |
724 | const char *label // IN: a label, when needed | |
725 | ) | |
726 | { | |
727 | RSA_KEY key; | |
728 | CRYPT_RESULT retVal = CRYPT_SUCCESS; | |
729 | UINT32 dSize; // Place to put temporary value for the | |
730 | // returned data size | |
731 | TPMI_ALG_HASH hashAlg = TPM_ALG_NULL; // hash algorithm in the selected | |
732 | // padding scheme | |
733 | TPM_RC result = TPM_RC_SUCCESS; | |
734 | ||
735 | // pointer checks | |
736 | pAssert( (dataOutSize != NULL) && (dataOut != NULL) | |
737 | && (rsaKey != NULL) && (cipherIn != NULL)); | |
738 | ||
739 | // The public type is a RSA decrypt key | |
740 | pAssert( (rsaKey->publicArea.type == TPM_ALG_RSA | |
741 | && rsaKey->publicArea.objectAttributes.decrypt == SET)); | |
742 | ||
743 | // Must have the private portion loaded. This check is made before this | |
744 | // function is called. | |
745 | pAssert(rsaKey->attributes.publicOnly == CLEAR); | |
746 | ||
747 | // decryption requires that the private modulus be present | |
748 | if(rsaKey->attributes.privateExp == CLEAR) | |
749 | { | |
750 | ||
751 | // Load key by computing the private exponent | |
752 | // CryptLoadPrivateRSA may return TPM_RC_BINDING | |
753 | result = CryptLoadPrivateRSA(rsaKey); | |
754 | } | |
755 | ||
756 | // the input buffer must be the size of the key | |
757 | if(result == TPM_RC_SUCCESS) | |
758 | { | |
759 | if(cipherInSize != rsaKey->publicArea.unique.rsa.t.size) | |
760 | result = TPM_RC_SIZE; | |
761 | else | |
762 | { | |
763 | BuildRSA(rsaKey, &key); | |
764 | ||
765 | // Initialize the dOutSize parameter | |
766 | dSize = *dataOutSize; | |
767 | ||
768 | // For OAEP scheme, initialize the hash algorithm for padding | |
769 | if(scheme->scheme == TPM_ALG_OAEP) | |
770 | { | |
771 | hashAlg = scheme->details.oaep.hashAlg; | |
772 | TEST_HASH(hashAlg); | |
773 | } | |
774 | // See if the padding mode needs to be tested | |
775 | TEST(scheme->scheme); | |
776 | ||
777 | // _cpri DecryptRSA may return CRYPT_PARAMETER CRYPT_FAIL CRYPT_SCHEME | |
778 | retVal = _cpri DecryptRSA(&dSize, dataOut, &key, scheme->scheme, | |
779 | cipherInSize, cipherIn, hashAlg, label); | |
780 | ||
781 | // Scheme must have been validated when the key was loaded/imported | |
782 | pAssert(retVal != CRYPT_SCHEME); | |
783 | ||
784 | // Set the return size |
785 | pAssert(dSize <= UINT16_MAX); | ||
786 | *dataOutSize = (UINT16)dSize; | ||
787 | |||
788 | // CRYPT_PARAMETER -> TPM_RC_VALUE, CRYPT_FAIL -> TPM_RC_VALUE | ||
789 | result = TranslateCryptErrors(retVal); | ||
790 | } | ||
791 | } | ||
792 | return result; | ||
793 | } |
This function provides the interface to _cpri__EncryptRSA(). The object referenced by rsaKey is required to be an RSA decryption key.
Error Returns | Meaning |
TPM_RC_SCHEME | scheme is not supported |
TPM_RC_VALUE | numeric value of dataIn is greater than the key modulus |
794 TPM_RC
795 CryptEncryptRSA(
796 UINT16 *cipherOutSize, // OUT: size of cipher text in byte 797 BYTE *cipherOut, // OUT: cipher text
798 OBJECT *rsaKey, // IN: internal RSA key
799 TPMT_RSA_DECRYPT *scheme, // IN: selects the padding scheme 800 UINT16 dataInSize, // IN: size of plain text in byte 801 BYTE *dataIn, // IN: plain text
802 const char *label // IN: an optional label 803 )
804 {
805 RSA_KEY key;
806 CRYPT_RESULT retVal;
807 UINT32 cOutSize; // Conversion variable
808 TPMI_ALG_HASH hashAlg = TPM_ALG_NULL; // hash algorithm in selected 809 // padding scheme
810
811 // must have a pointer to a key and some data to encrypt 812 pAssert(rsaKey != NULL && dataIn != NULL);
813
814 // The public type is a RSA decryption key
815 pAssert( rsaKey->publicArea.type == TPM_ALG_RSA
816 && rsaKey->publicArea.objectAttributes.decrypt == SET); 817
818 // If the cipher buffer must be provided and it must be large enough 819 // for the result
820 pAssert( cipherOut != NULL 821 && cipherOutSize != NULL
822 && *cipherOutSize >= rsaKey->publicArea.unique.rsa.t.size); 823
824 // Only need the public key and exponent for encryption 825 BuildRSA(rsaKey, &key);
826
827 // Copy the size to the conversion buffer 828 cOutSize = *cipherOutSize;
829
830 // For OAEP scheme, initialize the hash algorithm for padding 831 if(scheme->scheme == TPM_ALG_OAEP)
832 {
833 hashAlg = scheme->details.oaep.hashAlg;
834 TEST_HASH(hashAlg);
835 }
836
837 | // This is a public key operation and does not require that the private | key | |
838 | // be loaded. To verify this, need to do the full algorithm | ||
839 | TEST(scheme->scheme); | ||
840 | |||
841 | // Encrypt the data with the public exponent | ||
842 | // _cpri EncryptRSA may return CRYPT_PARAMETER or CRYPT_SCHEME | ||
843 | retVal = _cpri EncryptRSA(&cOutSize,cipherOut, &key, scheme->scheme, | ||
844 | dataInSize, dataIn, hashAlg, label); | ||
845 | |||
846 | pAssert (cOutSize <= UINT16_MAX); | ||
847 | *cipherOutSize = (UINT16)cOutSize; | ||
848 | // CRYPT_PARAMETER -> TPM_RC_VALUE, CRYPT_SCHEME -> TPM_RC_SCHEME | ||
849 | return TranslateCryptErrors(retVal); | ||
850 | } |
This function is used to sign a digest with an RSA signing key.
Error Returns | Meaning |
TPM_RC_BINDING | public and private part of signKey are not properly bound |
TPM_RC_SCHEME | scheme is not supported |
TPM_RC_VALUE | hashData is larger than the modulus of signKey, or the size of hashData does not match hash algorithm in scheme |
851 | static TPM_RC | |
852 | CryptSignRSA( | |
853 | OBJECT *signKey, // IN: RSA key signs the hash | |
854 | TPMT_SIG_SCHEME *scheme, // IN: sign scheme | |
855 | TPM2B_DIGEST *hashData, // IN: hash to be signed | |
856 | TPMT_SIGNATURE *sig // OUT: signature | |
857 | ) | |
858 | { | |
859 | UINT32 signSize; | |
860 | RSA_KEY key; | |
861 | CRYPT_RESULT retVal; | |
862 | TPM_RC result = TPM_RC_SUCCESS; | |
863 | ||
864 | pAssert( (signKey != NULL) && (scheme != NULL) | |
865 | && (hashData != NULL) && (sig != NULL)); | |
866 | ||
867 | // assume that the key has private part loaded and that it is a signing | key. |
868 | pAssert( (signKey->attributes.publicOnly == CLEAR) | |
869 | && (signKey->publicArea.objectAttributes.sign == SET)); | |
870 | ||
871 | // check if the private exponent has been computed | |
872 | if(signKey->attributes.privateExp == CLEAR) | |
873 | // May return TPM_RC_BINDING | |
874 | result = CryptLoadPrivateRSA(signKey); | |
875 | ||
876 | if(result == TPM_RC_SUCCESS) | |
877 | { | |
878 | BuildRSA(signKey, &key); | |
879 | ||
880 | // Make sure that the hash is tested | |
881 | TEST_HASH(sig->signature.any.hashAlg); | |
882 | ||
883 | // Run a test of the RSA sign | |
884 | TEST(scheme->scheme); | |
885 | ||
886 | // _crypi SignRSA can return CRYPT_SCHEME and CRYPT_PARAMETER | |
887 | retVal = _cpri SignRSA(&signSize, |
888 | sig->signature.rsassa.sig.t.buffer, | |
889 | &key, | |
890 | sig->sigAlg, | |
891 | sig->signature.any.hashAlg, | |
892 | hashData->t.size, hashData->t.buffer); | |
893 | pAssert(signSize <= UINT16_MAX); | |
894 | sig->signature.rsassa.sig.t.size = (UINT16)signSize; | |
895 | ||
896 | // CRYPT_SCHEME -> TPM_RC_SCHEME; CRYPT_PARAMTER -> TPM_RC_VALUE | |
897 | result = TranslateCryptErrors(retVal); | |
898 | } | |
899 | return result; | |
900 | } |
This function is used to verify signature signed by a RSA key.
Error Returns | Meaning |
TPM_RC_SIGNATURE | if signature is not genuine |
TPM_RC_SCHEME | signature scheme not supported |
901 static TPM_RC
902 CryptRSAVerifySignature(
903 OBJECT *signKey, // IN: RSA key signed the hash 904 TPM2B_DIGEST *digestData, // IN: digest being signed
905 TPMT_SIGNATURE *sig // IN: signature to be verified 906 )
907 {
908 RSA_KEY key;
909 CRYPT_RESULT retVal;
910 TPM_RC result;
911
912 // Validate parameter assumptions
913 pAssert((signKey != NULL) && (digestData != NULL) && (sig != NULL)); 914
915 TEST_HASH(sig->signature.any.hashAlg);
916 TEST(sig->sigAlg);
917
918 // This is a public-key-only operation 919 BuildRSA(signKey, &key);
920
921 // Call crypto engine to verify signature
922 // _cpri_ValidateSignaturRSA may return CRYPT_FAIL or CRYPT_SCHEME 923 retVal = _cpri ValidateSignatureRSA(&key,
sig->sigAlg,
sig->signature.any.hashAlg,
digestData->t.size,
digestData->t.buffer,
sig->signature.rsassa.sig.t.size,
sig->signature.rsassa.sig.t.buffer,
930 0);
931 // _cpri ValidateSignatureRSA can return CRYPT_SUCCESS, CRYPT_FAIL, or 932 // CRYPT_SCHEME. Translate CRYPT_FAIL to TPM_RC_SIGNATURE
933 if(retVal == CRYPT_FAIL)
934 result = TPM_RC_SIGNATURE;
935 else
936 // CRYPT_SCHEME -> TPM_RC_SCHEME
937 result = TranslateCryptErrors(retVal); 938
939 return result;
940 }
941 #endif //TPM_ALG_RSA //% 2
CryptEccGetCurveDataPointer()
This function returns a pointer to an ECC_CURVE_VALUES structure that contains the parameters for the key size and schemes for a given curve.
942 #ifdef TPM_ALG_ECC //% 3
943 static const ECC_CURVE *
944 CryptEccGetCurveDataPointer(
945 TPM_ECC_CURVE curveID // IN: id of the curve 946 )
947 {
948 return _cpri EccGetParametersByCurveId(curveID);
949 }
This function returns the size in bits of the key associated with a curve.
950 UINT16
951 CryptEccGetKeySizeInBits(
952 TPM_ECC_CURVE curveID // IN: id of the curve 953 )
954 {
955 const ECC_CURVE *curve = CryptEccGetCurveDataPointer(curveID); 956 UINT16 keySizeInBits = 0;
957
958 if(curve != NULL)
959 keySizeInBits = curve->keySizeBits; 960
961 return keySizeInBits;
962 }
This macro returns the size of the ECC key in bytes. It uses CryptEccGetKeySizeInBits().
963 | // The next lines will be placed in CyrptUtil_fp.h with the //% removed | |
964 | //% #define CryptEccGetKeySizeInBytes(curve) \ | |
965 | //% ((CryptEccGetKeySizeInBits(curve)+7)/8) | |
This function returns a pointer to an ECC curve parameter. The parameter is selected | by a single | |
character designator from the set of {pnabxyh}. | ||
966 | LIB_EXPORT const TPM2B * | |
967 | CryptEccGetParameter( | |
968 | char p, // IN: the parameter selector | |
969 | TPM_ECC_CURVE curveId // IN: the curve id | |
970 | ) | |
971 | { | |
972 | const ECC_CURVE *curve = _cpri EccGetParametersByCurveId(curveId); | |
973 | const TPM2B *parameter = NULL; | |
974 | ||
975 | if(curve != NULL) |
976 | { | |||
977 | switch (p) | |||
978 | { | |||
979 | case 'p': | |||
980 | parameter | = | curve->curveData->p; | |
981 | break; | |||
982 | case 'n': | |||
983 | parameter | = | curve->curveData->n; | |
984 | break; | |||
985 | case 'a': | |||
986 | parameter | = | curve->curveData->a; | |
987 | break; | |||
988 | case 'b': | |||
989 | parameter | = | curve->curveData->b; | |
990 | break; | |||
991 | case 'x': | |||
992 | parameter | = | curve->curveData->x; | |
993 | break; | |||
994 | case 'y': | |||
995 | parameter | = | curve->curveData->y; | |
996 | break; | |||
997 | case 'h': | |||
998 | parameter | = | curve->curveData->h; | |
999 | break; | |||
1000 | default: | |||
1001 | break; | |||
1002 | } |
1003 }
1004 return parameter;
1005 }
This function will return a pointer to the scheme of the curve.
1006 const TPMT_ECC_SCHEME *
1007 CryptGetCurveSignScheme(
1008 TPM_ECC_CURVE curveId // IN: The curve selector 1009 )
1010 {
1011 const ECC_CURVE *curve = _cpri EccGetParametersByCurveId(curveId); 1012 const TPMT_ECC_SCHEME *scheme = NULL;
1013
1014 if(curve != NULL)
1015 scheme = &(curve->sign); 1016 return scheme;
1017 }
This function will validate that an ECC point is on the curve of given curveID.
Return Value | Meaning |
TRUE | if the point is on curve |
FALSE | if the point is not on curve |
1018 | BOOL | |
1019 | CryptEccIsPointOnCurve( | |
1020 | TPM_ECC_CURVE curveID, | // IN: ECC curve ID |
1021 | TPMS_ECC_POINT *Q | // IN: ECC point |
1022 | ) |
1023 {
1024 // Make sure that point multiply is working 1025 TEST(TPM_ALG_ECC);
1026 // Check point on curve logic by seeing if the test key is on the curve 1027
1028 // Call crypto engine function to check if a ECC public point is on the 1029 // given curve
1030 if(_cpri EccIsPointOnCurve(curveID, Q))
1031 return TRUE;
1032 else
1033 return FALSE;
1034 }
This function creates a random ECC key that is not derived from other parameters as is a Primary Key.
1035 TPM_RC
1036 CryptNewEccKey(
1037 TPM_ECC_CURVE curveID, // IN: ECC curve 1038 TPMS_ECC_POINT *publicPoint, // OUT: public point 1039 TPM2B_ECC_PARAMETER *sensitive // OUT: private area 1040 )
1041 {
1042 TPM_RC result = TPM_RC_SUCCESS;
1043 // _cpri GetEphemeralECC may return CRYPT_PARAMETER
1044 if(_cpri GetEphemeralEcc(publicPoint, sensitive, curveID) != CRYPT_SUCCESS) 1045 // Something is wrong with the key.
1046 result = TPM_RC_KEY;
1047
1048 return result;
1049 }
This function is used to perform a point multiply R = [d]Q. If Q is not provided, the multiplication is performed using the generator point of the curve.
Error Returns | Meaning |
TPM_RC_ECC_POINT | invalid optional ECC point pIn |
TPM_RC_NO_RESULT | multiplication resulted in a point at infinity |
TPM_RC_CANCELED | if a self-test was done, it might have been aborted |
1050 | TPM_RC | |||
1051 | CryptEccPointMultiply( | |||
1052 | TPMS_ECC_POINT | *pOut, | // | OUT: output point |
1053 | TPM_ECC_CURVE | curveId, | // | IN: curve selector |
1054 | TPM2B_ECC_PARAMETER | *dIn, | // | IN: public scalar |
1055 | TPMS_ECC_POINT | *pIn | // | IN: optional point |
1056 | ) | |||
1057 | { | |||
1058 | TPM2B_ECC_PARAMETER | *n = NULL; | ||
1059 | CRYPT_RESULT | retVal; | ||
1060 | ||||
1061 | pAssert(pOut != NULL | && dIn != NULL); | ||
1062 | ||||
1063 | if(pIn != NULL) | |||
1064 | { | |||
1065 | n = dIn; | |||
1066 | dIn = NULL; |
1067 | } | |
1068 | // Do a test of point multiply | |
1069 | TEST(TPM_ALG_ECC); | |
1070 | ||
1071 | // _cpri EccPointMultiply may return CRYPT_POINT or CRYPT_NO_RESULT | |
1072 | retVal = _cpri EccPointMultiply(pOut, curveId, dIn, pIn, n); | |
1073 | ||
1074 | // CRYPT_POINT->TPM_RC_ECC_POINT and CRYPT_NO_RESULT->TPM_RC_NO_RESULT | |
1075 | return TranslateCryptErrors(retVal); | |
1076 | } |
This function generates an ECC key from a seed value.
The method here may not work for objects that have an order (G) that with a different size than a private key.
Error Returns | Meaning |
TPM_RC_VALUE | hash algorithm is not supported |
1077 static TPM_RC
1078 CryptGenerateKeyECC(
1079 TPMT_PUBLIC *publicArea, // IN/OUT: The public area template for the new 1080 // key.
1081 TPMT_SENSITIVE *sensitive, // IN/OUT: the sensitive area 1082 TPM_ALG_ID hashAlg, // IN: algorithm for the KDF 1083 TPM2B_SEED *seed, // IN: the seed value
1084 TPM2B_NAME *name, // IN: the name of the object 1085 UINT32 *counter // OUT: the iteration counter 1086 )
1087 {
1088 CRYPT_RESULT retVal;
1089
1090 TEST_HASH(hashAlg);
1091 TEST(ALG_ECDSA_VALUE); // ECDSA is used to verify each key 1092
1093 // The iteration counter has no meaning for ECC key generation. The parameter 1094 // will be overloaded for those implementations that have a requirement for 1095 // doing pair-wise consistency checks on signing keys. If the counter parameter 1096 // is 0 or NULL, then no consistency check is done. If it is other than 0, then 1097 // a consistency check is run. This modification allow this code to work with 1098 // the existing versions of the CrytpoEngine and with FIPS-compliant versions 1099 // as well.
1100 *counter = (UINT32)(publicArea->objectAttributes.sign == SET); 1101
1102 // _cpri GenerateKeyEcc only has one error return (CRYPT_PARAMETER) which means 1103 // that the hash algorithm is not supported. This should not be possible
1104 retVal = _cpri GenerateKeyEcc(&publicArea->unique.ecc, 1105 &sensitive->sensitive.ecc,
1106 publicArea->parameters.eccDetail.curveID,
1107 hashAlg, &seed->b, "ECC key by vendor",
1108 &name->b, counter);
1109 // This will only be useful if _cpri GenerateKeyEcc return CRYPT_CANCEL 1110 return TranslateCryptErrors(retVal);
1111 }
This function is used for ECC signing operations. If the signing scheme is a split scheme, and the signing operation is successful, the commit value is retired.
Error Returns | Meaning |
TPM_RC_SCHEME | unsupported scheme |
TPM_RC_VALUE | invalid commit status (in case of a split scheme) or failed to generate r value. |
1112 static TPM_RC
1113 CryptSignECC(
1114 OBJECT *signKey, // IN: ECC key to sign the hash 1115 TPMT_SIG_SCHEME *scheme, // IN: sign scheme
1116 TPM2B_DIGEST *hashData, // IN: hash to be signed 1117 TPMT_SIGNATURE *signature // OUT: signature
1118 )
1119 {
1120 TPM2B_ECC_PARAMETER r;
1121 TPM2B_ECC_PARAMETER *pr = NULL;
1122 CRYPT_RESULT retVal;
1123
1124 // Run a test of the ECC sign and verify if it has not already been run 1125 TEST_HASH(scheme->details.any.hashAlg);
1126 TEST(scheme->scheme);
1127
1128 if(CryptIsSplitSign(scheme->scheme))
1129 {
1130 // When this code was written, the only split scheme was ECDAA 1131 // (which can also be used for U-Prove).
1132 if(!CryptGenerateR(&r,
1133 &scheme->details.ecdaa.count,
1134 signKey->publicArea.parameters.eccDetail.curveID,
1135 &signKey->name))
1136 return TPM_RC_VALUE; 1137 pr = &r;
1138 | } | |
1139 | // Call crypto engine function to sign | |
1140 | // _cpri SignEcc may return CRYPT_SCHEME | |
1141 | retVal = _cpri SignEcc(&signature->signature.ecdsa.signatureR, | |
1142 | &signature->signature.ecdsa.signatureS, | |
1143 | scheme->scheme, | |
1144 | scheme->details.any.hashAlg, | |
1145 | signKey->publicArea.parameters.eccDetail.curveID, | |
1146 | &signKey->sensitive.sensitive.ecc, | |
1147 | &hashData->b, | |
1148 | pr | |
1149 | ); | |
1150 | if(CryptIsSplitSign(scheme->scheme) && retVal == CRYPT_SUCCESS) | |
1151 | CryptEndCommit(scheme->details.ecdaa.count); | |
1152 | // CRYPT_SCHEME->TPM_RC_SCHEME | |
1153 | return TranslateCryptErrors(retVal); | |
1154 | } |
This function is used to verify a signature created with an ECC key.
Error Returns | Meaning |
TPM_RC_SIGNATURE | if signature is not valid |
TPM_RC_SCHEME | the signing scheme or hashAlg is not supported |
1155 | static TPM_RC | |
1156 | CryptECCVerifySignature( | |
1157 | OBJECT *signKey, | // IN: ECC key signed the hash |
1158 | TPM2B_DIGEST *digestData, // IN: digest being signed | |
1159 | TPMT_SIGNATURE *signature // IN: signature to be verified | |
1160 | ) | |
1161 | { | |
1162 | CRYPT_RESULT retVal; | |
1163 | ||
1164 | TEST_HASH(signature->signature.any.hashAlg); | |
1165 | TEST(signature->sigAlg); | |
1166 | ||
1167 | // This implementation uses the fact that all the defined ECC signing | |
1168 | // schemes have the hash as the first parameter. | |
1169 | // _cpriValidateSignatureEcc may return CRYPT_FAIL or CRYP_SCHEME | |
1170 | retVal = _cpri ValidateSignatureEcc(&signature->signature.ecdsa.signatureR, | |
1171 | &signature->signature.ecdsa.signatureS, | |
1172 | signature->sigAlg, | |
1173 | signature->signature.any.hashAlg, | |
1174 | signKey->publicArea.parameters.eccDetail.curveID, | |
1175 | &signKey->publicArea.unique.ecc, | |
1176 | &digestData->b); | |
1177 | if(retVal == CRYPT_FAIL) | |
1178 | return TPM_RC_SIGNATURE; | |
1179 | // CRYPT_SCHEME->TPM_RC_SCHEME | |
1180 | return TranslateCryptErrors(retVal); | |
1181 | } |
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.
Return Value | Meaning |
TRUE | r value computed |
FALSE | no r value computed |
1182 BOOL
1183 CryptGenerateR(
1184 TPM2B_ECC_PARAMETER *r, // OUT: the generated random value 1185 UINT16 *c, // IN/OUT: count value.
1186 TPMI_ECC_CURVE curveID, // IN: the curve for the value 1187 TPM2B_NAME *name // IN: optional name of a key to 1188 // associate with 'r'
1189 )
1190 {
1191 // This holds the marshaled g_commitCounter. 1192 TPM2B_TYPE(8B, 8);
1193 TPM2B_8B cntr = {8,{0}};
1194
1195 UINT32 iterations;
1196 const TPM2B *n;
1197 UINT64 currentCount = gr.commitCounter;
1198 // This is just to suppress a compiler warning about a conditional expression 1199 // being a constant. This is because of the macro expansion of ryptKDFa
1200 TPMI_ALG_HASH hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
1201
1202 n = CryptEccGetParameter('n', curveID); 1203 pAssert(r != NULL && n != NULL);
1204
1205 // If this is the commit phase, use the current value of the commit counter 1206 if(c != NULL)
1207 | { | |
1208 | ||
1209 | UINT16 t1; | |
1210 | // if the array bit is not set, can't use the value. | |
1211 | if(!BitIsSet((*c & COMMIT_INDEX_MASK), gr.commitArray, | |
1212 | sizeof(gr.commitArray))) | |
1213 | return FALSE; | |
1214 | ||
1215 | // If it is the sign phase, figure out what the counter value was | |
1216 | // when the commitment was made. | |
1217 | // | |
1218 | // When gr.commitArray has less than 64K bits, the extra | |
1219 | // bits of 'c' are used as a check to make sure that the | |
1220 | // signing operation is not using an out of range count value | |
1221 | t1 = (UINT16)currentCount; | |
1222 | ||
1223 | // If the lower bits of c are greater or equal to the lower bits of t1 | |
1224 | // then the upper bits of t1 must be one more than the upper bits | |
1225 | // of c | |
1226 | if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK)) | |
1227 | // Since the counter is behind, reduce the current count | |
1228 | currentCount = currentCount - (COMMIT_INDEX_MASK + 1); | |
1229 | ||
1230 | t1 = (UINT16)currentCount; | |
1231 | if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK)) | |
1232 | return FALSE; | |
1233 | // set the counter to the value that was | |
1234 | // present when the commitment was made | |
1235 | currentCount = (currentCount & 0xffffffffffff0000) | *c; | |
1236 | ||
1237 | } | |
1238 | // Marshal the count value to a TPM2B buffer for the KDF | |
1239 | cntr.t.size = sizeof(currentCount); | |
1240 | UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer); | |
1241 | ||
1242 | // Now can do the KDF to create the random value for the signing operation | |
1243 | // During the creation process, we may generate an r that does not meet the | |
1244 | // requirements of the random value. | |
1245 | // want to generate a new r. | |
1246 | ||
1247 | r->t.size = n->size; | |
1248 | ||
1249 | // Arbitrary upper limit on the number of times that we can look for | |
1250 | // a suitable random value. The normally number of tries will be 1. | |
1251 | for(iterations = 1; iterations < 1000000;) | |
1252 | { | |
1253 | BYTE *pr = &r->b.buffer[0]; | |
1254 | int i; | |
1255 | CryptKDFa(hashAlg, &gr.commitNonce.b, "ECDAA Commit", | |
1256 | name, &cntr.b, n->size * 8, r->t.buffer, &iterations); | |
1257 | ||
1258 | // random value must be less than the prime | |
1259 | if(CryptCompare(r->b.size, r->b.buffer, n->size, n->buffer) >= 0) | |
1260 | continue; | |
1261 | ||
1262 | // in this implementation it is required that at least bit | |
1263 | // in the upper half of the number be set | |
1264 | for(i = n->size/2; i > 0; i--) | |
1265 | if(*pr++ != 0) | |
1266 | return TRUE; | |
1267 | } | |
1268 | return FALSE; | |
1269 | } |
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.
1270 UINT16
1271 CryptCommit(
1272 void
1273 )
1274 {
1275 UINT16 oldCount = (UINT16)gr.commitCounter; 1276 gr.commitCounter++;
1277 BitSet(oldCount & COMMIT_INDEX_MASK, gr.commitArray, sizeof(gr.commitArray)); 1278 return oldCount;
1279 }
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.
1280 void
1281 CryptEndCommit(
1282 UINT16 c // IN: the counter value of the commitment 1283 )
1284 {
1285 BitClear((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray)); 1286 }
This function performs the computations for the TPM2_Commit() command. This could be a macro.
Error Returns | Meaning |
TPM_RC_NO_RESULT | K, L, or E is the point at infinity |
TPM_RC_CANCELLED | command was canceled |
1287 | TPM_RC | ||||
1288 | CryptCommitCompute( | ||||
1289 | TPMS_ECC_POINT | *K, | // | OUT: | [d]B |
1290 | TPMS_ECC_POINT | *L, | // | OUT: | [r]B |
1291 | TPMS_ECC_POINT | *E, | // | OUT: | [r]M |
1292 | TPM_ECC_CURVE | curveID, | // | IN: | The curve for the computation |
1293 | TPMS_ECC_POINT | *M, | // | IN: | M (P1) |
1294 | TPMS_ECC_POINT | *B, | // | IN: | B (x2, y2) |
1295 | TPM2B_ECC_PARAMETER | *d, | // | IN: | the private scalar |
1296 | TPM2B_ECC_PARAMETER | *r | // | IN: | the computed r value |
1297 | ) | ||||
1298 | { | ||||
1299 | TEST(ALG_ECDH_VALUE); | ||||
1300 | // CRYPT_NO_RESULT->TPM_RC_NO_RESULT | CRYPT_CANCEL->TPM_RC_CANCELLED | |||
1301 | return TranslateCryptErrors( | ||||
1302 | urveID, M, B, d, r)); | ||||
1303 | } |
_cpri EccCommitCompute(K, L , E, c
This function returns the ECC parameter details of the given curve
Return Value | Meaning |
TRUE | Get parameters success |
FALSE | Unsupported ECC curve ID |
1304 | BOOL | ||
1305 | CryptEccGetParameters( | ||
1306 | TPM_ECC_CURVE | curveId, | // IN: ECC curve ID |
1307 | TPMS_ALGORITHM_DETAIL_ECC | *parameters | // OUT: ECC parameter |
1308 | ) | ||
1309 | { | ||
1310 | const | ECC_CURVE | *curve = _cpri EccGetParametersByCurveId(curveId); |
1311 | const | ECC_CURVE_DATA | *data; |
1312 BOOL found = curve != NULL; 1313
1314 if(found)
1315 {
1316
1317 | data = curve->curveData; | |
1318 | ||
1319 | parameters->curveID = curve->curveId; | |
1320 | ||
1321 | // Key size in bit | |
1322 | parameters->keySize = curve->keySizeBits; | |
1323 | ||
1324 | // KDF | |
1325 | parameters->kdf = curve->kdf; | |
1326 | ||
1327 | // Sign | |
1328 | parameters->sign = curve->sign; | |
1329 | ||
1330 | // Copy p value | |
1331 | MemoryCopy2B(¶meters->p.b, data->p, sizeof(parameters->p.t.buffer)); | |
1332 | ||
1333 | // Copy a value | |
1334 | MemoryCopy2B(¶meters->a.b, data->a, sizeof(parameters->a.t.buffer)); | |
1335 | ||
1336 | // Copy b value | |
1337 | MemoryCopy2B(¶meters->b.b, data->b, sizeof(parameters->b.t.buffer)); | |
1338 | ||
1339 | // Copy Gx value | |
1340 | MemoryCopy2B(¶meters->gX.b, data->x, sizeof(parameters->gX.t.buffer)); | |
1341 | ||
1342 | // Copy Gy value | |
1343 | MemoryCopy2B(¶meters->gY.b, data->y, sizeof(parameters->gY.t.buffer)); | |
1344 | ||
1345 | // Copy n value | |
1346 | MemoryCopy2B(¶meters->n.b, data->n, sizeof(parameters->n.t.buffer)); | |
1347 | ||
1348 | // Copy h value | |
1349 | MemoryCopy2B(¶meters->h.b, data->h, sizeof(parameters->h.t.buffer)); | |
1350 | } | |
1351 | return found; | |
1352 | } | |
1353 | #if | CC_ZGen_2Phase == YES |
CryptEcc2PhaseKeyExchange() This is the interface to the key exchange function.
1354 TPM_RC
1355 CryptEcc2PhaseKeyExchange(
1356 TPMS_ECC_POINT *outZ1, // OUT: the computed point 1357 TPMS_ECC_POINT *outZ2, // OUT: optional second point 1358 TPM_ALG_ID scheme, // IN: the key exchange scheme
1359 TPM_ECC_CURVE curveId, // IN: the curve for the computation 1360 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
1361 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key 1362 TPMS_ECC_POINT *QsB, // IN: static public party B key 1363 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key 1364 )
1365 {
1366 return (TranslateCryptErrors(_cpri C_2_2_KeyExchange(outZ1,
1367 outZ2,
1368 scheme,
1369 curveId,
1370 dsA,
1371 deA,
1372 QsB,
1373 QeB)));
1374 }
1375 #endif // CC_ZGen_2Phase 1376 #endif //TPM_ALG_ECC //% 3
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.
1377 BOOL
1378 CryptIsSchemeAnonymous(
1379 TPM_ALG_ID scheme // IN: the scheme algorithm to test 1380 )
1381 {
1382 #ifdef TPM_ALG_ECDAA
1383 return (scheme == TPM_ALG_ECDAA); 1384 #else
1385 UNREFERENCED(scheme);
1386 return 0;
1387 #endif
1388 }
This function performs parameter decryption using symmetric block cipher.
1389 void
1390 ParmDecryptSym(
1391 TPM_ALG_ID symAlg, // IN: the symmetric algorithm 1392 TPM_ALG_ID hash, // IN: hash algorithm for KDFa 1393 UINT16 keySizeInBits, // IN: key key size in bit 1394 TPM2B *key, // IN: KDF HMAC key
1395 TPM2B *nonceCaller, // IN: nonce caller 1396 TPM2B *nonceTpm, // IN: nonce TPM
1397 UINT32 dataSize, // IN: size of parameter buffer 1398 BYTE *data // OUT: buffer to be decrypted 1399 )
1400 {
1401 // KDF output buffer
1402 // It contains parameters for the CFB encryption 1403 // From MSB to LSB, they are the key and iv
1404 BYTE symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
1405 // Symmetric key size in byte
1406 UINT16 keySize = (keySizeInBits + 7) / 8;
1407 TPM2B_IV iv;
1408
1409 iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits); 1410 // If there is decryption to do...
1411 if(iv.t.size > 0)
1412 {
1413 // Generate key and iv
1414 CryptKDFa(hash, key, "CFB", nonceCaller, nonceTpm,
1415 keySizeInBits + (iv.t.size * 8), symParmString, NULL); 1416 MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size,
1417 sizeof(iv.t.buffer));
1418
1419 CryptSymmetricDecrypt(data, symAlg, keySizeInBits, TPM_ALG_CFB, 1420 symParmString, &iv, dataSize, data); 1421 }
1422 return;
1423 }
This function performs parameter encryption using symmetric block cipher.
1424 void
1425 ParmEncryptSym(
1426 TPM_ALG_ID symAlg, // IN: symmetric algorithm 1427 TPM_ALG_ID hash, // IN: hash algorithm for KDFa 1428 UINT16 keySizeInBits, // IN: AES key size in bit 1429 TPM2B *key, // IN: KDF HMAC key
1430 TPM2B *nonceCaller, // IN: nonce caller 1431 TPM2B *nonceTpm, // IN: nonce TPM
1432 UINT32 dataSize, // IN: size of parameter buffer 1433 BYTE *data // OUT: buffer to be encrypted 1434 )
1435 {
1436 // KDF output buffer
1437 // It contains parameters for the CFB encryption
1438 BYTE symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
1439
1440 // Symmetric key size in bytes
1441 UINT16 keySize = (keySizeInBits + 7) / 8;
1442
1443 TPM2B_IV iv;
1444
1445 iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits); 1446 // See if there is any encryption to do
1447 if(iv.t.size > 0)
1448 {
1449 // Generate key and iv
1450 CryptKDFa(hash, key, "CFB", nonceTpm, nonceCaller,
1451 keySizeInBits + (iv.t.size * 8), symParmString, NULL); 1452
1453 MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size, 1454 sizeof(iv.t.buffer));
1455
1456 CryptSymmetricEncrypt(data, symAlg, keySizeInBits, TPM_ALG_CFB, 1457 symParmString, &iv, dataSize, data); 1458 }
1459 return;
1460 }
This function creates the sensitive symmetric values for an HMAC or symmetric key. If the sensitive area is zero, then the sensitive creation key data is copied. If it is not zero, then the TPM will generate a random value of the selected size.
1461 void
1462 CryptGenerateNewSymmetric(
1463 TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation data 1464 TPMT_SENSITIVE *sensitive, // OUT: sensitive area
1465 TPM_ALG_ID hashAlg, // IN: hash algorithm for the KDF 1466 TPM2B_SEED *seed, // IN: seed used in creation
1467 TPM2B_NAME *name // IN: name of the object 1468 )
1469 {
1470 // This function is called to create a key and obfuscation value for a
1471 // symmetric key that can either be a block cipher or an XOR key. The buffer 1472 // in sensitive->sensitive will hold either. When we call the function
1473 // to copy the input value or generated value to the sensitive->sensitive 1474 // buffer we will need to have a size for the output buffer. This define
1475 // computes the maximum that it might need to be and uses that. It will always 1476 // be smaller than the largest value that will fit.
1477 #define MAX_SENSITIVE_SIZE \
1478 (MAX(sizeof(sensitive->sensitive.bits.t.buffer), \
1479 sizeof(sensitive->sensitive.sym.t.buffer)))
1480
1481 // set the size of the obfuscation value
1482 sensitive->seedValue.t.size = CryptGetHashDigestSize(hashAlg); 1483
1484 // If the input sensitive size is zero, then create both the sensitive data 1485 // and the obfuscation value
1486 if(sensitiveCreate->data.t.size == 0)
1487 {
1488 BYTE symValues[MAX(MAX_DIGEST_SIZE, MAX_SYM_KEY_BYTES)
1489 + MAX_DIGEST_SIZE];
1490 UINT16 requestSize;
1491
1492 // Set the size of the request to be the size of the key and the 1493 // obfuscation value
1494 requestSize = sensitive->sensitive.sym.t.size 1495 + sensitive->seedValue.t.size; 1496 pAssert(requestSize <= sizeof(symValues));
1497
1498 requestSize = _cpri GenerateSeededRandom(requestSize, symValues, hashAlg, 1499 &seed->b,
1500 "symmetric sensitive", &name->b,
1501 NULL);
1502 pAssert(requestSize != 0);
1503
1504 // Copy the new key
1505 MemoryCopy(sensitive->sensitive.sym.t.buffer,
1506 symValues, sensitive->sensitive.sym.t.size,
1507 MAX_SENSITIVE_SIZE);
1508
1509 // copy the obfuscation value
1510 MemoryCopy(sensitive->seedValue.t.buffer,
1511 &symValues[sensitive->sensitive.sym.t.size],
1512 sensitive->seedValue.t.size,
1513 sizeof(sensitive->seedValue.t.buffer));
1514 }
1515 else
1516 {
1517 // Copy input symmetric key to sensitive area as long as it will fit 1518 MemoryCopy2B(&sensitive->sensitive.sym.b, &sensitiveCreate->data.b,
1519 MAX_SENSITIVE_SIZE);
1521 | // Create the obfuscation value | |
1522 | _cpri GenerateSeededRandom(sensitive->seedValue.t.size, | |
1523 | sensitive->seedValue.t.buffer, | |
1524 | hashAlg, &seed->b, | |
1525 | "symmetric obfuscation", &name->b, NULL); | |
1526 | } | |
1527 | return; | |
1528 | } |
This function derives a symmetric cipher key from the provided seed.
Error Returns | Meaning |
TPM_RC_KEY_SIZE | key size in the public area does not match the size in the sensitive creation area |
1529 static TPM_RC
1530 CryptGenerateKeySymmetric(
1531 TPMT_PUBLIC *publicArea, // IN/OUT: The public area template 1532 // for the new key.
1533 TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation data 1534 TPMT_SENSITIVE *sensitive, // OUT: sensitive area
1535 TPM_ALG_ID hashAlg, // IN: hash algorithm for the KDF 1536 TPM2B_SEED *seed, // IN: seed used in creation
1537 TPM2B_NAME *name // IN: name of the object 1538 )
1539 {
1540 // If this is not a new key, then the provided key data must be the right size 1541 if(publicArea->objectAttributes.sensitiveDataOrigin == CLEAR)
1542 {
1543 if( (sensitiveCreate->data.t.size * 8)
1544 != publicArea->parameters.symDetail.sym.keyBits.sym)
1545 return TPM_RC_KEY_SIZE;
1546 // Make sure that the key size is OK.
1547 // This implementation only supports symmetric key sizes that are 1548 // multiples of 8
1549 if(publicArea->parameters.symDetail.sym.keyBits.sym % 8 != 0)
1550 return TPM_RC_KEY_SIZE;
1551 }
1552 else
1553 {
1554 // TPM is going to generate the key so set the size 1555 sensitive->sensitive.sym.t.size
1556 = publicArea->parameters.symDetail.sym.keyBits.sym / 8;
1557 sensitiveCreate->data.t.size = 0;
1558 }
1559 // Fill in the sensitive area
1560 CryptGenerateNewSymmetric(sensitiveCreate, sensitive, hashAlg, 1561 seed, name);
1562
1563 // Create unique area in public
1564 CryptComputeSymmetricUnique(publicArea->nameAlg,
1565 sensitive, &publicArea->unique.sym);
1566
1567 return TPM_RC_SUCCESS;
1568 }
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.
1569 #ifdef TPM_ALG_KEYEDHASH //% 5
1570 void
1571 CryptXORObfuscation(
1572 TPM_ALG_ID hash, // IN: hash algorithm for KDF 1573 TPM2B *key, // IN: KDF key
1574 TPM2B *contextU, // IN: contextU 1575 TPM2B *contextV, // IN: contextV
1576 UINT32 dataSize, // IN: size of data buffer
1577 BYTE *data // IN/OUT: data to be XORed in place 1578 )
1579 {
1580 BYTE mask[MAX_DIGEST_SIZE]; // Allocate a digest sized buffer 1581 BYTE *pm;
1582 UINT32 i;
1583 UINT32 counter = 0;
1584 UINT16 hLen = CryptGetHashDigestSize(hash); 1585 UINT32 requestSize = dataSize * 8;
1586 INT32 remainBytes = (INT32) dataSize; 1587
1588 pAssert((key != NULL) && (data != NULL) && (hLen != 0)); 1589
1590 // Call KDFa to generate XOR mask
1591 for(; remainBytes > 0; remainBytes -= hLen) 1592 {
1593 // Make a call to KDFa to get next iteration
1594 CryptKDFaOnce(hash, key, "XOR", contextU, contextV, 1595 requestSize, mask, &counter);
1596
1597 // XOR next piece of the data
1598 pm = mask;
1599 for(i = hLen < remainBytes ? hLen : remainBytes; i > 0; i--) 1600 *data++ ^= *pm++;
1601 }
1602 return;
1603 }
1604 #endif //TPM_ALG_KEYED_HASH //%5
This function is called when the TPM receives a _TPM_Init() indication. After function returns, the hash algorithms should be available.
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.
1605 void
1606 CryptInitUnits(
1607 void
1608 )
1609 {
1610 // Initialize the vector of implemented algorithms
1611 AlgorithmGetImplementedVector(&g_implementedAlgorithms);
1612
1613 // Indicate that all test are necessary 1614 CryptInitializeToTest();
1615
1616 // Call crypto engine unit initialization
1617 // It is assumed that crypt engine initialization should always succeed. 1618 // Otherwise, TPM should go to failure mode.
1619 if(_cpri InitCryptoUnits(&TpmFail) != CRYPT_SUCCESS) 1620 FAIL(FATAL_ERROR_INTERNAL);
1621 return;
1622 }
This function is only used in a simulated environment. There should be no reason to shut down the cryptography on an actual TPM other than loss of power. After receiving TPM2_Startup(), the TPM should be able to accept commands until it loses power and, unless the TPM is in Failure Mode, the cryptographic algorithms should be available.
1623 void
1624 CryptStopUnits(
1625 void
1626 )
1627 {
1628 // Call crypto engine unit stopping 1629 _cpri StopCryptoUnits();
1630
1631 return;
1632 }
This function is called by TPM2_Startup() to initialize the functions in this crypto library and in the provided CryptoEngine(). In this implementation, the only initialization required in this library is initialization of the Commit nonce on TPM Reset.
This function returns false if some problem prevents the functions from starting correctly. The TPM should go into failure mode.
1633 BOOL
1634 CryptUtilStartup(
1635 STARTUP_TYPE type // IN: the startup type 1636 )
1637 {
1638 // Make sure that the crypto library functions are ready. 1639 // NOTE: need to initialize the crypto before loading 1640 // the RND state may trigger a self-test which
1641 // uses the
1642 if( !_cpri Startup())
1643 return FALSE;
1644
1645 // Initialize the state of the RNG. 1646 CryptDrbgGetPutState(PUT_STATE);
1647
1648 if(type == SU_RESET)
1649 {
1650 #ifdef TPM_ALG_ECC
1651 // Get a new random commit nonce
1652 gr.commitNonce.t.size = sizeof(gr.commitNonce.t.buffer);
1653 _cpri GenerateRandom(gr.commitNonce.t.size, gr.commitNonce.t.buffer); 1654 // Reset the counter and commit array
1655 gr.commitCounter = 0;
1656 MemorySet(gr.commitArray, 0, sizeof(gr.commitArray)); 1657 #endif // TPM_ALG_ECC
1658 }
1659
1660 // If the shutdown was orderly, then the values recovered from NV will
1661 // be OK to use. If the shutdown was not orderly, then a TPM Reset was required 1662 // and we would have initialized in the code above.
1663
1664 return TRUE;
1665 }
Algorithm-Independent Functions
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.
This function indicates if an algorithm is an asymmetric algorithm.
Return Value | Meaning |
TRUE | if it is an asymmetric algorithm |
FALSE | if it is not an asymmetric algorithm |
1666 | BOOL | |
1667 | CryptIsAsymAlgorithm( | |
1668 | TPM_ALG_ID algID | // IN: algorithm ID |
1669 | ) | |
1670 | { | |
1671 | return ( | |
1672 | #ifdef TPM_ALG_RSA | |
1673 | algID == TPM_ALG_RSA |
1674 #endif
1675 #if defined TPM_ALG_RSA && defined TPM_ALG_ECC 1676 ||
1677 #endif
1678 #ifdef TPM_ALG_ECC
1679 algID == TPM_ALG_ECC
1680 #endif
1681 );
1682 }
This function returns the size in octets of the symmetric encryption block used by an algorithm and key size combination.
1683 INT16
1684 CryptGetSymmetricBlockSize(
1685 TPMI_ALG_SYM algorithm, // IN: symmetric algorithm 1686 UINT16 keySize // IN: key size in bit 1687 )
1688 {
1689 return _cpri GetSymmetricBlockSize(algorithm, keySize); 1690 }
This function does in-place encryption of a buffer using the indicated symmetric algorithm, key, IV, and mode. If the symmetric algorithm and mode are not defined, the TPM will fail.
1691 void
1692 CryptSymmetricEncrypt(
1693 BYTE *encrypted, // OUT: the encrypted data
1694 TPM_ALG_ID algorithm, // IN: algorithm for encryption 1695 UINT16 keySizeInBits, // IN: key size in bit
1696 TPMI_ALG_SYM_MODE mode, // IN: symmetric encryption mode 1697 BYTE *key, // IN: encryption key
1698 TPM2B_IV *ivIn, // IN/OUT: Input IV and output chaining 1699 // value for the next block
1700 UINT32 dataSize, // IN: data size in byte
1701 BYTE *data // IN/OUT: data buffer 1702 )
1703 {
1704
1705 TPM2B_IV defaultIv = {0};
1706 TPM2B_IV *iv = (ivIn != NULL) ? ivIn : &defaultIv; 1707
1708 TEST(algorithm);
1709
1710 pAssert(encrypted != NULL && key != NULL); 1711
1712 // this check can pass but the case below can fail. ALG_xx_VALUE values are 1713 // defined for all algorithms but the TPM_ALG_xx might not be.
1714 if(algorithm == ALG_AES_VALUE || algorithm == ALG_SM4_VALUE) 1715 {
1716 if(mode != TPM_ALG_ECB) 1717 defaultIv.t.size = 16;
1718 // A provided IV has to be the right size
1719 pAssert(mode == TPM_ALG_ECB || iv->t.size == 16); 1720 }
1721 switch(algorithm)
1722 {
1723 #ifdef TPM_ALG_AES
1724 case TPM_ALG_AES:
1725 {
1726 switch (mode)
1727 {
1728 case TPM_ALG_CTR:
1729 _cpri AESEncryptCTR(encrypted, keySizeInBits, key,
1730 iv->t.buffer, dataSize, data);
1731 break;
1732 case TPM_ALG_OFB:
1733 _cpri AESEncryptOFB(encrypted, keySizeInBits, key,
1734 iv->t.buffer, dataSize, data);
1735 break;
1736 case TPM_ALG_CBC:
1737 _cpri AESEncryptCBC(encrypted, keySizeInBits, key,
1738 iv->t.buffer, dataSize, data);
1739 break;
1740 case TPM_ALG_CFB:
1741 _cpri AESEncryptCFB(encrypted, keySizeInBits, key,
1742 iv->t.buffer, dataSize, data);
1743 break;
1744 case TPM_ALG_ECB:
1745 _cpri AESEncryptECB(encrypted, keySizeInBits, key, 1746 dataSize, data);
1747 break;
1748 default:
1749 pAssert(0);
1750 }
1751 }
1752 break;
1753 #endif
1754 #ifdef TPM_ALG_SM4
1755 case TPM_ALG_SM4:
1756 {
1757 switch (mode)
1758 {
1759 case TPM_ALG_CTR:
1760 _cpri SM4EncryptCTR(encrypted, keySizeInBits, key,
1761 iv->t.buffer, dataSize, data);
1762 break;
1763 case TPM_ALG_OFB:
1764 _cpri SM4EncryptOFB(encrypted, keySizeInBits, key,
1765 iv->t.buffer, dataSize, data);
1766 break;
1767 case TPM_ALG_CBC:
1768 _cpri SM4EncryptCBC(encrypted, keySizeInBits, key,
1769 iv->t.buffer, dataSize, data);
1770 break;
1771
1772 case TPM_ALG_CFB:
1773 _cpri SM4EncryptCFB(encrypted, keySizeInBits, key,
1774 iv->t.buffer, dataSize, data);
1775 break;
1776 case TPM_ALG_ECB:
1777 _cpri SM4EncryptECB(encrypted, keySizeInBits, key, 1778 dataSize, data);
1779 break;
1780 default:
1781 pAssert(0);
1782 }
1783 }
1784 break;
1785
1786 #endif
1787 default:
1788 pAssert(FALSE);
1789 break;
1790 }
1791
1792 return;
1793
1794 }
This function does in-place decryption of a buffer using the indicated symmetric algorithm, key, IV, and mode. If the symmetric algorithm and mode are not defined, the TPM will fail.
1795 void
1796 CryptSymmetricDecrypt(
1797 BYTE *decrypted,
1798 TPM_ALG_ID algorithm, // IN: algorithm for encryption 1799 UINT16 keySizeInBits, // IN: key size in bit
1800 TPMI_ALG_SYM_MODE mode, // IN: symmetric encryption mode 1801 BYTE *key, // IN: encryption key
1802 TPM2B_IV *ivIn, // IN/OUT: IV for next block 1803 UINT32 dataSize, // IN: data size in byte
1804 BYTE *data // IN/OUT: data buffer 1805 )
1806 {
1807 BYTE *iv = NULL;
1808 BYTE defaultIV[sizeof(TPMT_HA)];
1810 TEST(algorithm);
1811
1812 if(
1813 #ifdef TPM_ALG_AES
1814 algorithm == TPM_ALG_AES 1815 #endif
1816 #if defined TPM_ALG_AES && defined TPM_ALG_SM4 1817 ||
1818 #endif
1819 #ifdef TPM_ALG_SM4
1820 algorithm == TPM_ALG_SM4 1821 #endif
1822 )
1823 {
1824 // Both SM4 and AES have block size of 128 bits 1825 // If the iv is not provided, create a default of 0 1826 if(ivIn == NULL)
1827 {
1828 // Initialize the default IV
1829 iv = defaultIV;
1830 MemorySet(defaultIV, 0, 16);
1831 }
1832 else
1833 {
1834 // A provided IV has to be the right size
1835 pAssert(mode == TPM_ALG_ECB || ivIn->t.size == 16);
1836 iv = &(ivIn->t.buffer[0]); 1837 }
1838 }
1839
1840 switch(algorithm)
1841 {
1842 #ifdef TPM_ALG_AES
1843 case TPM_ALG_AES:
1844 {
1845
1846 switch (mode)
1847 {
1848 case TPM_ALG_CTR:
1849 _cpri AESDecryptCTR(decrypted, keySizeInBits, key, iv, 1850 dataSize, data);
1851 break;
1852 case TPM_ALG_OFB:
1853 _cpri AESDecryptOFB(decrypted, keySizeInBits, key, iv, 1854 dataSize, data);
1855 break;
1856 case TPM_ALG_CBC:
1857 _cpri AESDecryptCBC(decrypted, keySizeInBits, key, iv, 1858 dataSize, data);
1859 break;
1860 case TPM_ALG_CFB:
1861 _cpri AESDecryptCFB(decrypted, keySizeInBits, key, iv, 1862 dataSize, data);
1863 break;
1864 case TPM_ALG_ECB:
1865 _cpri AESDecryptECB(decrypted, keySizeInBits, key, 1866 dataSize, data);
1867 break;
1868 default:
1869 pAssert(0);
1870 }
1871 break;
1872 }
1873 #endif //TPM_ALG_AES
1874 #ifdef TPM_ALG_SM4
1875 case TPM_ALG_SM4 :
1876 switch (mode)
1877 {
1878 case TPM_ALG_CTR:
1879 _cpri SM4DecryptCTR(decrypted, keySizeInBits, key, iv, 1880 dataSize, data);
1881 break;
1882 case TPM_ALG_OFB:
1883 _cpri SM4DecryptOFB(decrypted, keySizeInBits, key, iv, 1884 dataSize, data);
1885 break;
1886 case TPM_ALG_CBC:
1887 _cpri SM4DecryptCBC(decrypted, keySizeInBits, key, iv, 1888 dataSize, data);
1889 break;
1890 case TPM_ALG_CFB:
1891 _cpri SM4DecryptCFB(decrypted, keySizeInBits, key, iv, 1892 dataSize, data);
1893 break;
1894 case TPM_ALG_ECB:
1895 _cpri SM4DecryptECB(decrypted, keySizeInBits, key, 1896 dataSize, data);
1897 break;
1898 default:
1899 pAssert(0);
1900 }
1901 break;
1902 #endif //TPM_ALG_SM4
1903
1904 default:
1905 pAssert(FALSE);
1906 break;
1907 }
1908 return;
1909 }
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().
Error Returns | Meaning |
TPM_RC_ATTRIBUTES | keyHandle does not reference a valid decryption key |
TPM_RC_KEY | invalid ECC key (public point is not on the curve) |
TPM_RC_SCHEME | RSA key with an unsupported padding scheme |
TPM_RC_VALUE | numeric value of the data to be decrypted is greater than the RSA key modulus |
1910 TPM_RC
1911 CryptSecretEncrypt(
1912 TPMI_DH_OBJECT keyHandle, // IN: encryption key handle
1913 const char *label, // IN: a null-terminated string as L 1914 TPM2B_DATA *data, // OUT: secret value
1915 TPM2B_ENCRYPTED_SECRET *secret // OUT: secret structure 1916 )
1917 {
1918 TPM_RC result = TPM_RC_SUCCESS;
1919 OBJECT *encryptKey = ObjectGet(keyHandle); // TPM key used for encrypt 1920
1921 pAssert(data != NULL && secret != NULL);
1922
1923 // The output secret value has the size of the digest produced by the nameAlg. 1924 data->t.size = CryptGetHashDigestSize(encryptKey->publicArea.nameAlg);
1925
1926 pAssert(encryptKey->publicArea.objectAttributes.decrypt == SET); 1927
1928 switch(encryptKey->publicArea.type)
1929 {
1930 #ifdef TPM_ALG_RSA
1931 case TPM_ALG_RSA:
1932 {
1933 TPMT_RSA_DECRYPT scheme;
1934
1935 // Use OAEP scheme
1936 scheme.scheme = TPM_ALG_OAEP;
1937 scheme.details.oaep.hashAlg = encryptKey->publicArea.nameAlg; 1938
1939 // Create secret data from RNG
1940 CryptGenerateRandom(data->t.size, data->t.buffer);
1941
1942 // Encrypt the data by RSA OAEP into encrypted secret
1943 result = CryptEncryptRSA(&secret->t.size, secret->t.secret, 1944 encryptKey, &scheme,
1945 data->t.size, data->t.buffer, label); 1946 }
1947 break;
1948 #endif //TPM_ALG_RSA
1949
1950 #ifdef TPM_ALG_ECC
1951 case TPM_ALG_ECC:
1952 {
1953 TPMS_ECC_POINT eccPublic;
1954 TPM2B_ECC_PARAMETER eccPrivate;
1955 TPMS_ECC_POINT eccSecret;
1956 BYTE *buffer = secret->t.secret; 1957
1958 // Need to make sure that the public point of the key is on the 1959 // curve defined by the key.
1960 if(!_cpri EccIsPointOnCurve(
1961 encryptKey->publicArea.parameters.eccDetail.curveID,
1962 &encryptKey->publicArea.unique.ecc)) 1963 result = TPM_RC_KEY;
1964 else
1965 {
1966
1967 // Call crypto engine to create an auxiliary ECC key
1968 // We assume crypt engine initialization should always success.
1969 // Otherwise, TPM should go to failure mode.
1970 CryptNewEccKey(encryptKey->publicArea.parameters.eccDetail.curveID,
1971 &eccPublic, &eccPrivate);
1972
1973 // Marshal ECC public to secret structure. This will be used by the
1974 // recipient to decrypt the secret with their private key.
1975 secret->t.size = TPMS_ECC_POINT_Marshal(&eccPublic, &buffer, NULL); 1976
1977 // Compute ECDH shared secret which is R = [d]Q where d is the
1978 // private part of the ephemeral key and Q is the public part of a
1979 // TPM key. TPM_RC_KEY error return from CryptComputeECDHSecret
1980 // because the auxiliary ECC key is just created according to the
1981 // parameters of input ECC encrypt key.
1982 if( CryptEccPointMultiply(&eccSecret,
1983 encryptKey->publicArea.parameters.eccDetail.curveID,
1984 &eccPrivate,
1985 &encryptKey->publicArea.unique.ecc)
1986 != CRYPT_SUCCESS)
1987 result = TPM_RC_KEY;
1988 else
1989
1990 // The secret value is computed from Z using KDFe as:
1991 // secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
1992 // Where:
1993 // HashID the nameAlg of the decrypt key
1994 // Z the x coordinate (Px) of the product (P) of the point
1995 // (Q) of the secret and the private x coordinate (de,V)
1996 // of the decryption key
1997 // Use a null-terminated string containing "SECRET"
1998 // PartyUInfo the x coordinate of the point in the secret
1999 // (Qe,U )
2000 // PartyVInfo the x coordinate of the public key (Qs,V )
2001 // bits the number of bits in the digest of HashID
2002 // Retrieve seed from KDFe 2003
2004 CryptKDFe(encryptKey->publicArea.nameAlg, &eccSecret.x.b,
2005 label, &eccPublic.x.b,
2006 &encryptKey->publicArea.unique.ecc.x.b,
2007 data->t.size * 8, data->t.buffer);
2008 }
2009 }
2010 break;
2011 #endif //TPM_ALG_ECC
2012
2013 default:
2014 FAIL(FATAL_ERROR_INTERNAL);
2015 break;
2016 }
2017
2018 return result;
2019 }
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
Error Returns | Meaning |
TPM_RC_ATTRIBUTES | RSA key is not a decryption key |
TPM_RC_BINDING | Invalid RSA key (public and private parts are not cryptographically bound. |
TPM_RC_ECC_POINT | ECC point in the secret is not on the curve |
TPM_RC_INSUFFICIENT | failed to retrieve ECC point from the secret |
TPM_RC_NO_RESULT | multiplication resulted in ECC point at infinity |
TPM_RC_SIZE | data to decrypt is not of the same size as RSA key |
TPM_RC_VALUE | For RSA key, numeric value of the encrypted data is greater than the modulus, or the recovered data is larger than the output buffer. For keyedHash or symmetric key, the secret is larger than the size of the digest produced by the name algorithm. |
TPM_RC_FAILURE | internal error |
2020 | TPM_RC | ||||
2021 | CryptSecretDecrypt( | ||||
2022 | TPM_HANDLE | tpmKey, | // | IN: | decrypt key |
2023 | TPM2B_NONCE | *nonceCaller, | // | IN: | nonceCaller. It is needed for |
2024 | // | symmetric decryption. For |
2025 // asymmetric decryption, this
2026 // parameter is NULL
2027 const char *label, // IN: a null-terminated string as L 2028 TPM2B_ENCRYPTED_SECRET *secret, // IN: input secret
2029 TPM2B_DATA *data // OUT: decrypted secret value 2030 )
2031 {
2032 TPM_RC result = TPM_RC_SUCCESS;
2033 OBJECT *decryptKey = ObjectGet(tpmKey); //TPM key used for decrypting 2034
2035 // Decryption for secret
2036 switch(decryptKey->publicArea.type)
2037 {
2038
2039 #ifdef TPM_ALG_RSA
2040 case TPM_ALG_RSA:
2041 {
2042 TPMT_RSA_DECRYPT scheme;
2043
2044 // Use OAEP scheme
2045 scheme.scheme = TPM_ALG_OAEP;
2046 scheme.details.oaep.hashAlg = decryptKey->publicArea.nameAlg; 2047
2048 // Set the output buffer capacity
2049 data->t.size = sizeof(data->t.buffer); 2050
2051 // Decrypt seed by RSA OAEP
2052 result = CryptDecryptRSA(&data->t.size, data->t.buffer, decryptKey, 2053 &scheme,
2054 secret->t.size, secret->t.secret,label); 2055 if( (result == TPM_RC_SUCCESS)
2056 && (data->t.size
2057 > CryptGetHashDigestSize(decryptKey->publicArea.nameAlg))) 2058 result = TPM_RC_VALUE;
2059 }
2060 break;
2061 #endif //TPM_ALG_RSA
2062
2063 #ifdef TPM_ALG_ECC
2064 case TPM_ALG_ECC:
2065 {
2066 TPMS_ECC_POINT eccPublic;
2067 TPMS_ECC_POINT eccSecret;
2068 BYTE *buffer = secret->t.secret;
2069 INT32 size = secret->t.size; 2070
2071 // Retrieve ECC point from secret buffer
2072 result = TPMS_ECC_POINT_Unmarshal(&eccPublic, &buffer, &size); 2073 if(result == TPM_RC_SUCCESS)
2074 {
2075 result = CryptEccPointMultiply(&eccSecret,
2076 decryptKey->publicArea.parameters.eccDetail.curveID,
2077 &decryptKey->sensitive.sensitive.ecc,
2078 &eccPublic);
2079
2080 if(result == TPM_RC_SUCCESS)
2081 {
2082
2083 // Set the size of the "recovered" secret value to be the size
2084 // of the digest produced by the nameAlg.
2085 data->t.size =
2086 CryptGetHashDigestSize(decryptKey->publicArea.nameAlg);
2087
2088 // The secret value is computed from Z using KDFe as:
2089 // secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
2090 // Where:
2091 | // HashID -- the nameAlg of the decrypt key | |
2092 | // Z -- the x coordinate (Px) of the product (P) of the point | |
2093 | // (Q) of the secret and the private x coordinate (de,V) | |
2094 | // of the decryption key | |
2095 | // Use -- a null-terminated string containing "SECRET" | |
2096 | // PartyUInfo -- the x coordinate of the point in the secret | |
2097 | // (Qe,U ) | |
2098 | // PartyVInfo -- the x coordinate of the public key (Qs,V ) | |
2099 | // bits -- the number of bits in the digest of HashID | |
2100 | // Retrieve seed from KDFe | |
2101 | CryptKDFe(decryptKey->publicArea.nameAlg, &eccSecret.x.b, label, | |
2102 | &eccPublic.x.b, | |
2103 | &decryptKey->publicArea.unique.ecc.x.b, | |
2104 | data->t.size * 8, data->t.buffer); | |
2105 | } | |
2106 | } | |
2107 | } | |
2108 | break; | |
2109 | #endif | //TPM_ALG_ECC |
2110 | ||
2111 | case TPM_ALG_KEYEDHASH: | |
2112 | // The seed size can not be bigger than the digest size of nameAlg | |
2113 | if(secret->t.size > | |
2114 | CryptGetHashDigestSize(decryptKey->publicArea.nameAlg)) | |
2115 | result = TPM_RC_VALUE; | |
2116 | else | |
2117 | { | |
2118 | // Retrieve seed by XOR Obfuscation: | |
2119 | // seed = XOR(secret, hash, key, nonceCaller, nullNonce) | |
2120 | // where: | |
2121 | // secret the secret parameter from the TPM2_StartAuthHMAC | |
2122 | // command | |
2123 | // which contains the seed value | |
2124 | // hash nameAlg of tpmKey | |
2125 | // key the key or data value in the object referenced by | |
2126 | // entityHandle in the TPM2_StartAuthHMAC command | |
2127 | // nonceCaller the parameter from the TPM2_StartAuthHMAC command | |
2128 | // nullNonce a zero-length nonce | |
2129 | // XOR Obfuscation in place | |
2130 | CryptXORObfuscation(decryptKey->publicArea.nameAlg, | |
2131 | &decryptKey->sensitive.sensitive.bits.b, | |
2132 | &nonceCaller->b, NULL, | |
2133 | secret->t.size, secret->t.secret); | |
2134 | // Copy decrypted seed | |
2135 | MemoryCopy2B(&data->b, &secret->b, sizeof(data->t.buffer)); | |
2136 | } | |
2137 | break; | |
2138 | case TPM_ALG_SYMCIPHER: | |
2139 | { | |
2140 | TPM2B_IV iv = {0}; | |
2141 | TPMT_SYM_DEF_OBJECT *symDef; | |
2142 | // The seed size can not be bigger than the digest size of nameAlg | |
2143 | if(secret->t.size > | |
2144 | CryptGetHashDigestSize(decryptKey->publicArea.nameAlg)) | |
2145 | result = TPM_RC_VALUE; | |
2146 | else | |
2147 | { | |
2148 | symDef = &decryptKey->publicArea.parameters.symDetail.sym; | |
2149 | iv.t.size = CryptGetSymmetricBlockSize(symDef->algorithm, | |
2150 | symDef->keyBits.sym); | |
2151 | pAssert(iv.t.size != 0); | |
2152 | if(nonceCaller->t.size >= iv.t.size) | |
2153 | MemoryCopy(iv.t.buffer, nonceCaller->t.buffer, iv.t.size, | |
2154 | sizeof(iv.t.buffer)); | |
2155 | else | |
2156 | MemoryCopy(iv.b.buffer, nonceCaller->t.buffer, |
2157 nonceCaller->t.size, sizeof(iv.t.buffer)); 2158 // CFB decrypt in place, using nonceCaller as iv
2159 CryptSymmetricDecrypt(secret->t.secret, symDef->algorithm,
2160 symDef->keyBits.sym, TPM_ALG_CFB,
2161 decryptKey->sensitive.sensitive.sym.t.buffer,
2162 &iv, secret->t.size, secret->t.secret); 2163
2164 // Copy decrypted seed
2165 MemoryCopy2B(&data->b, &secret->b, sizeof(data->t.buffer)); 2166 }
2167 }
2168 break;
2169 default:
2170 pAssert(0);
2171 break;
2172 }
2173 return result;
2174 }
This function does in-place encryption of a response parameter.
2175 void
2176 CryptParameterEncryption(
2177 TPM_HANDLE handle, // IN: encrypt session handle 2178 TPM2B *nonceCaller, // IN: nonce caller
2179 UINT16 leadingSizeInByte, // IN: the size of the leading size field in 2180 // byte
2181 TPM2B_AUTH *extraKey, // IN: additional key material other than 2182 // session auth
2183 BYTE *buffer // IN/OUT: parameter buffer to be encrypted 2184 )
2185 {
2186 SESSION *session = SessionGet(handle); // encrypt session 2187 TPM2B_TYPE(SYM_KEY, ( sizeof(extraKey->t.buffer)
2188 + sizeof(session->sessionKey.t.buffer))); 2189 TPM2B_SYM_KEY key; // encryption key
2190 UINT32 cipherSize = 0; // size of cipher text 2191
2192 pAssert(session->sessionKey.t.size + extraKey->t.size <= sizeof(key.t.buffer)); 2193
2194 // Retrieve encrypted data size. 2195 if(leadingSizeInByte == 2)
2196 {
2197 // Extract the first two bytes as the size field as the data size 2198 // encrypt
2199 cipherSize = (UINT32)BYTE_ARRAY_TO_UINT16(buffer); 2200 // advance the buffer
2201 buffer = &buffer[2]; 2202 }
2203 #ifdef TPM4B
2204 else if(leadingSizeInByte == 4)
2205 {
2206 // use the first four bytes to indicate the number of bytes to encrypt 2207 cipherSize = BYTE_ARRAY_TO_UINT32(buffer);
2208 //advance pointer
2209 buffer = &buffer[4]; 2210 }
2211 #endif
2212 else
2213 {
2214 pAssert(FALSE);
2215 }
2216 | ||
2217 | // Compute encryption key by concatenating sessionAuth with extra key | |
2218 | MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer)); | |
2219 | MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer)); | |
2220 | ||
2221 | if (session->symmetric.algorithm == TPM_ALG_XOR) | |
2222 | ||
2223 | // XOR parameter encryption formulation: | |
2224 | // XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder) | |
2225 | CryptXORObfuscation(session->authHashAlg, &(key.b), | |
2226 | &(session->nonceTPM.b), | |
2227 | nonceCaller, cipherSize, buffer); | |
2228 | else | |
2229 | ParmEncryptSym(session->symmetric.algorithm, session->authHashAlg, | |
2230 | session->symmetric.keyBits.aes, &(key.b), | |
2231 | nonceCaller, &(session->nonceTPM.b), | |
2232 | cipherSize, buffer); | |
2233 | return; | |
2234 | } |
This function does in-place decryption of a command parameter.
Error Returns | Meaning |
TPM_RC_SIZE | The number of bytes in the input buffer is less than the number of bytes to be decrypted. |
2235 TPM_RC
2236 CryptParameterDecryption(
2237 TPM_HANDLE handle, // IN: encrypted session handle 2238 TPM2B *nonceCaller, // IN: nonce caller
2239 UINT32 bufferSize, // IN: size of parameter buffer
2240 UINT16 leadingSizeInByte, // IN: the size of the leading size field in 2241 // byte
2242 TPM2B_AUTH *extraKey, // IN: the authValue
2243 BYTE *buffer // IN/OUT: parameter buffer to be decrypted 2244 )
2245 {
2246 SESSION *session = SessionGet(handle); // encrypt session
2247 // The HMAC key is going to be the concatenation of the session key and any 2248 // additional key material (like the authValue). The size of both of these 2249 // is the size of the buffer which can contain a TPMT_HA.
2250 TPM2B_TYPE(HMAC_KEY, ( sizeof(extraKey->t.buffer)
2251 + sizeof(session->sessionKey.t.buffer))); 2252 TPM2B_HMAC_KEY key; // decryption key
2253 UINT32 cipherSize = 0; // size of cipher text 2254
2255 pAssert(session->sessionKey.t.size + extraKey->t.size <= sizeof(key.t.buffer)); 2256
2257 // Retrieve encrypted data size. 2258 if(leadingSizeInByte == 2)
2259 {
2260 // The first two bytes of the buffer are the size of the 2261 // data to be decrypted
2262 cipherSize = (UINT32)BYTE_ARRAY_TO_UINT16(buffer); 2263 buffer = &buffer[2]; // advance the buffer
2264 }
2265 #ifdef TPM4B
2266 else if(leadingSizeInByte == 4)
2267 {
2268 // the leading size is four bytes so get the four byte size field 2269 cipherSize = BYTE_ARRAY_TO_UINT32(buffer);
2270 buffer = &buffer[4]; //advance pointer 2271 }
2272 #endif
2273 else
2274 {
2275 pAssert(FALSE);
2276 }
2277 if(cipherSize > bufferSize) 2278 return TPM_RC_SIZE;
2279
2280 // Compute decryption key by concatenating sessionAuth with extra input key 2281 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
2282 MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer)); 2283
2284 if(session->symmetric.algorithm == TPM_ALG_XOR) 2285 // XOR parameter decryption formulation:
2286 // XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder) 2287 // Call XOR obfuscation function
2288 CryptXORObfuscation(session->authHashAlg, &key.b, nonceCaller,
2289 &(session->nonceTPM.b), cipherSize, buffer); 2290 else
2291 // Assume that it is one of the symmetric block ciphers.
2292 ParmDecryptSym(session->symmetric.algorithm, session->authHashAlg,
2293 session->symmetric.keyBits.sym,
2294 &key.b, nonceCaller, &session->nonceTPM.b,
2295 cipherSize, buffer);
2296
2297 return TPM_RC_SUCCESS;
2298
2299 }
CryptComputeSymmetricUnique()
This function computes the unique field in public area for symmetric objects.
2300 void
2301 CryptComputeSymmetricUnique(
2302 TPMI_ALG_HASH nameAlg, // IN: object name algorithm 2303 TPMT_SENSITIVE *sensitive, // IN: sensitive area
2304 TPM2B_DIGEST *unique // OUT: unique buffer 2305 )
2306 {
2307 HASH_STATE hashState;
2308
2309 pAssert(sensitive != NULL && unique != NULL); 2310
2311 // Compute the public value as the hash of sensitive.symkey || unique.buffer 2312 unique->t.size = CryptGetHashDigestSize(nameAlg);
2313 CryptStartHash(nameAlg, &hashState);
2314
2315 // Add obfuscation value
2316 CryptUpdateDigest2B(&hashState, &sensitive->seedValue.b);
2317
2318 // Add sensitive value
2319 CryptUpdateDigest2B(&hashState, &sensitive->sensitive.any.b);
2320
2321 CryptCompleteHash2B(&hashState, &unique->b);
2322
2323 return;
2324 }
2325 #if 0 //%
This function computes the seedValue field in asymmetric sensitive areas.
2326 void
2327 CryptComputeSymValue(
2328 TPM_HANDLE parentHandle, // IN: parent handle of the object to be created 2329 TPMT_PUBLIC *publicArea, // IN/OUT: the public area template
2330 TPMT_SENSITIVE *sensitive, // IN: sensitive area 2331 TPM2B_SEED *seed, // IN: the seed
2332 TPMI_ALG_HASH hashAlg, // IN: hash algorithm for KDFa 2333 TPM2B_NAME *name // IN: object name
2334 )
2335 {
2336 TPM2B_AUTH *proof = NULL;
2337
2338 if(CryptIsAsymAlgorithm(publicArea->type))
2339 {
2340 // Generate seedValue only when an asymmetric key is a storage key 2341 if(publicArea->objectAttributes.decrypt == SET
2342 && publicArea->objectAttributes.restricted == SET) 2343 {
2344 // If this is a primary object in the endorsement hierarchy, use 2345 // ehProof in the creation of the symmetric seed so that child 2346 // objects in the endorsement hierarchy are voided on TPM2_Clear() 2347 // or TPM2_ChangeEPS()
2348 if( parentHandle == TPM_RH_ENDORSEMENT
2349 && publicArea->objectAttributes.fixedTPM == SET)
2350 proof = &gp.ehProof; 2351 }
2352 else
2353 {
2354 sensitive->seedValue.t.size = 0;
2355 return;
2356 }
2357 }
2358
2359 // For all object types, the size of seedValue is the digest size of nameAlg 2360 sensitive->seedValue.t.size = CryptGetHashDigestSize(publicArea->nameAlg); 2361
2362 // Compute seedValue using implementation-dependent method 2363 _cpri GenerateSeededRandom(sensitive->seedValue.t.size,
2364 sensitive->seedValue.t.buffer,
2365 hashAlg,
2366 &seed->b,
2367 "seedValue",
2368 &name->b,
2369 (TPM2B *)proof);
2370 return;
2371 }
2372 #endif //%
This function creates an object. It:
fills in the created key in public and sensitive area;
creates a random number in sensitive area for symmetric keys; and
compute the unique id in public area for symmetric keys.
Error Returns | Meaning |
TPM_RC_KEY_SIZE | key size in the public area does not match the size in the sensitive creation area for a symmetric key |
TPM_RC_RANGE | for an RSA key, the exponent is not supported |
TPM_RC_SIZE | sensitive data size is larger than allowed for the scheme for a keyed hash object |
TPM_RC_VALUE | exponent is not prime or could not find a prime using the provided parameters for an RSA key; unsupported name algorithm for an ECC key |
2373 TPM_RC
2374 CryptCreateObject(
2375 TPM_HANDLE parentHandle, // IN/OUT: indication of the seed 2376 // source
2377 TPMT_PUBLIC *publicArea, // IN/OUT: public area 2378 TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation 2379 TPMT_SENSITIVE *sensitive // OUT: sensitive area 2380 )
2381 {
2382 // Next value is a placeholder for a random seed that is used in
2383 // key creation when the parent is not a primary seed. It has the same 2384 // size as the primary seed.
2385
2386 TPM2B_SEED localSeed; // data to seed key creation if this 2387 // is not a primary seed
2388
2389 TPM2B_SEED *seed = NULL;
2390 TPM_RC result = TPM_RC_SUCCESS;
2391
2392 TPM2B_NAME name;
2393 TPM_ALG_ID hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
2394 OBJECT *parent;
2395 UINT32 counter;
2396
2397 // Set the sensitive type for the object 2398 sensitive->sensitiveType = publicArea->type; 2399 ObjectComputeName(publicArea, &name);
2400
2401 // For all objects, copy the initial auth data 2402 sensitive->authValue = sensitiveCreate->userAuth; 2403
2404 // If this is a permanent handle assume that it is a hierarchy 2405 if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
2406 {
2407 seed = HierarchyGetPrimarySeed(parentHandle); 2408 }
2409 else
2410 {
2411 // If not hierarchy handle, get parent
2412 parent = ObjectGet(parentHandle);
2413 hashAlg = parent->publicArea.nameAlg; 2414
2415 // Use random value as seed for non-primary objects 2416 localSeed.t.size = PRIMARY_SEED_SIZE;
2417 CryptGenerateRandom(PRIMARY_SEED_SIZE, localSeed.t.buffer); 2418 seed = &localSeed;
2419 }
2420
2421 switch(publicArea->type)
2422 {
2423 #ifdef TPM_ALG_RSA
2424 // Create RSA key
2425 case TPM_ALG_RSA:
2426 result = CryptGenerateKeyRSA(publicArea, sensitive,
2427 hashAlg, seed, &name, &counter);
2428 break;
2429 #endif // TPM_ALG_RSA
2430
2431 #ifdef TPM_ALG_ECC
2432 // Create ECC key 2433 case TPM_ALG_ECC:
2434 result = CryptGenerateKeyECC(publicArea, sensitive,
2435 hashAlg, seed, &name, &counter);
2436 break;
2437 #endif // TPM_ALG_ECC
2438
2439 // Collect symmetric key information 2440 case TPM_ALG_SYMCIPHER:
2441 return CryptGenerateKeySymmetric(publicArea, sensitiveCreate,
2442 sensitive, hashAlg, seed, &name);
2443 break;
2444 case TPM_ALG_KEYEDHASH:
2445 return CryptGenerateKeyedHash(publicArea, sensitiveCreate,
2446 sensitive, hashAlg, seed, &name);
2447 break;
2448 default:
2449 pAssert(0);
2450 break;
2451 }
2452 if(result == TPM_RC_SUCCESS)
2453 {
2454 TPM2B_AUTH *proof = NULL;
2455
2456 if(publicArea->objectAttributes.decrypt == SET
2457 && publicArea->objectAttributes.restricted == SET) 2458 {
2459 // If this is a primary object in the endorsement hierarchy, use 2460 // ehProof in the creation of the symmetric seed so that child 2461 // objects in the endorsement hierarchy are voided on TPM2_Clear() 2462 // or TPM2_ChangeEPS()
2463 if( parentHandle == TPM_RH_ENDORSEMENT
2464 && publicArea->objectAttributes.fixedTPM == SET)
2465 proof = &gp.ehProof; 2466
2467 // For all object types, the size of seedValue is the digest size 2468 // of its nameAlg
2469 sensitive->seedValue.t.size
2470 = CryptGetHashDigestSize(publicArea->nameAlg);
2471
2472 // Compute seedValue using implementation-dependent method 2473 _cpri GenerateSeededRandom(sensitive->seedValue.t.size,
2474 sensitive->seedValue.t.buffer,
2475 hashAlg,
2476 &seed->b,
2477 "seedValuea",
2478 &name.b,
2479 (TPM2B *)proof);
2480 }
2481 else
2482 {
2483 sensitive->seedValue.t.size = 0;
2484 }
2485 }
2486
2487 return result;
2488
2489 }
CryptObjectIsPublicConsistent()
This function checks that the key sizes in the public area are consistent. For an asymmetric key, the size of the public key must match the size indicated by the public->parameters.
Checks for the algorithm types matching the key type are handled by the unmarshaling operation.
Return Value | Meaning |
TRUE | sizes are consistent |
FALSE | sizes are not consistent |
2490 BOOL
2491 CryptObjectIsPublicConsistent(
2492 TPMT_PUBLIC *publicArea // IN: public area 2493 )
2494 {
2495 BOOL OK = TRUE;
2496 switch (publicArea->type)
2497 {
2498 #ifdef TPM_ALG_RSA
2499 case TPM_ALG_RSA:
2500 OK = CryptAreKeySizesConsistent(publicArea);
2501 break;
2502 #endif //TPM_ALG_RSA
2503
2504 #ifdef TPM_ALG_ECC
2505 case TPM_ALG_ECC:
2506 {
2507 const ECC_CURVE *curveValue; 2508
2509 // Check that the public point is on the indicated curve.
2510 OK = CryptEccIsPointOnCurve(
2511 publicArea->parameters.eccDetail.curveID,
2512 &publicArea->unique.ecc);
2513 if(OK)
2514 {
2515 curveValue = CryptEccGetCurveDataPointer(
2516 publicArea->parameters.eccDetail.curveID); 2517 pAssert(curveValue != NULL);
2518
2519 // The input ECC curve must be a supported curve
2520 // IF a scheme is defined for the curve, then that scheme must
2521 // be used.
2522 OK = (curveValue->sign.scheme == TPM_ALG_NULL
2523 || ( publicArea->parameters.eccDetail.scheme.scheme 2524 == curveValue->sign.scheme));
2525 OK = OK && CryptAreKeySizesConsistent(publicArea); 2526 }
2527 }
2528 break;
2529 #endif //TPM_ALG_ECC
2530
2531 default:
2532 // Symmetric object common checks
2533 // There is noting to check with a symmetric key that is public only. 2534 // Also not sure that there is anything useful to be done with it 2535 // either.
2536 break;
2537 }
2538 return OK;
2539 }
CryptObjectPublicPrivateMatch()
This function checks the cryptographic binding between the public and sensitive areas.
Error Returns | Meaning |
TPM_RC_TYPE | the type of the public and private areas are not the same |
TPM_RC_FAILURE | crypto error |
TPM_RC_BINDING | the public and private areas are not cryptographically matched. |
2540 | TPM_RC | |
2541 | CryptObjectPublicPrivateMatch( | |
2542 | OBJECT *object // IN: the object to check | |
2543 | ) | |
2544 | { | |
2545 | TPMT_PUBLIC *publicArea; | |
2546 | TPMT_SENSITIVE *sensitive; | |
2547 | TPM_RC result = TPM_RC_SUCCESS; | |
2548 | BOOL isAsymmetric = FALSE; | |
2549 | ||
2550 | pAssert(object != NULL); | |
2551 | publicArea = &object->publicArea; | |
2552 | sensitive = &object->sensitive; | |
2553 | if(publicArea->type != sensitive->sensitiveType) | |
2554 | return TPM_RC_TYPE; | |
2555 | ||
2556 | switch(publicArea->type) | |
2557 | { | |
2558 | #ifdef TPM_ALG_RSA | |
2559 | case TPM_ALG_RSA: | |
2560 | isAsymmetric = TRUE; | |
2561 | // The public and private key sizes need to be consistent | |
2562 | if(sensitive->sensitive.rsa.t.size != publicArea->unique.rsa.t.size/2) | |
2563 | result = TPM_RC_BINDING; | |
2564 | else | |
2565 | // Load key by computing the private exponent | |
2566 | result = CryptLoadPrivateRSA(object); | |
2567 | break; | |
2568 | #endif | |
2569 | #ifdef TPM_ALG_ECC | |
2570 | // This function is called from ObjectLoad() which has already checked | to |
2571 | // see that the public point is on the curve so no need to repeat that | |
2572 | // check. | |
2573 | case TPM_ALG_ECC: | |
2574 | isAsymmetric = TRUE; | |
2575 | if( publicArea->unique.ecc.x.t.size | |
2576 | != sensitive->sensitive.ecc.t.size) | |
2577 | result = TPM_RC_BINDING; | |
2578 | else if(publicArea->nameAlg != TPM_ALG_NULL) | |
2579 | { | |
2580 | TPMS_ECC_POINT publicToCompare; | |
2581 | // Compute ECC public key | |
2582 | CryptEccPointMultiply(&publicToCompare, | |
2583 | publicArea->parameters.eccDetail.curveID, | |
2584 | &sensitive->sensitive.ecc, NULL); | |
2585 | // Compare ECC public key | |
2586 | if( (!Memory2BEqual(&publicArea->unique.ecc.x.b, | |
2587 | &publicToCompare.x.b)) | |
2588 | || (!Memory2BEqual(&publicArea->unique.ecc.y.b, | |
2589 | &publicToCompare.y.b))) | |
2590 | result = TPM_RC_BINDING; | |
2591 | } | |
2592 | break; |
2594 | case TPM_ALG_KEYEDHASH: | |
2595 | break; | |
2596 | case TPM_ALG_SYMCIPHER: | |
2597 | if( (publicArea->parameters.symDetail.sym.keyBits.sym + 7)/8 | |
2598 | != sensitive->sensitive.sym.t.size) | |
2599 | result = TPM_RC_BINDING; | |
2600 | break; | |
2601 | default: | |
2602 | // The choice here is an assert or a return of a bad type for the object | |
2603 | pAssert(0); | |
2604 | break; | |
2605 | } | |
2606 | ||
2607 | // For asymmetric keys, the algorithm for validating the linkage between | |
2608 | // the public and private areas is algorithm dependent. For symmetric keys | |
2609 | // the linkage is based on hashing the symKey and obfuscation values. | |
2610 | if( result == TPM_RC_SUCCESS && !isAsymmetric | |
2611 | && publicArea->nameAlg != TPM_ALG_NULL) | |
2612 | { | |
2613 | TPM2B_DIGEST uniqueToCompare; | |
2614 | ||
2615 | // Compute unique for symmetric key | |
2616 | CryptComputeSymmetricUnique(publicArea->nameAlg, sensitive, | |
2617 | &uniqueToCompare); | |
2618 | // Compare unique | |
2619 | if(!Memory2BEqual(&publicArea->unique.sym.b, | |
2620 | &uniqueToCompare.b)) | |
2621 | result = TPM_RC_BINDING; | |
2622 | } | |
2623 | return result; | |
2624 | ||
2625 | } |
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
2626 TPMI_ALG_HASH
2627 CryptGetSignHashAlg(
2628 TPMT_SIGNATURE *auth // IN: signature 2629 )
2630 {
2631 pAssert(auth->sigAlg != TPM_ALG_NULL); 2632
2633 // Get authHash algorithm based on signing scheme 2634 switch(auth->sigAlg)
2635 {
2636
2637 #ifdef TPM_ALG_RSA
2638 case TPM_ALG_RSASSA:
2639 return auth->signature.rsassa.hash;
2640
2641 case TPM_ALG_RSAPSS:
2642 return auth->signature.rsapss.hash;
2643
2644 #endif //TPM_ALG_RSA
2645
2646 #ifdef TPM_ALG_ECC
2647 case TPM_ALG_ECDSA:
2648 return auth->signature.ecdsa.hash;
2649
2650 #endif //TPM_ALG_ECC
2651
2652 case TPM_ALG_HMAC:
2653 return auth->signature.hmac.hashAlg;
2654
2655 default:
2656 return TPM_ALG_NULL;
2657 }
2658 }
This function us used to determine if the signing operation is a split signing operation that required a TPM2_Commit().
2659 BOOL
2660 CryptIsSplitSign(
2661 TPM_ALG_ID scheme // IN: the algorithm selector 2662 )
2663 {
2664 if( scheme != scheme 2665 # ifdef TPM_ALG_ECDAA
2666 || scheme == TPM_ALG_ECDAA
2667 # endif // TPM_ALG_ECDAA
2668
2669 )
2670 return TRUE;
2671 return FALSE;
2672 }
This function indicates if a scheme algorithm is a sign algorithm.
2673 BOOL
2674 CryptIsSignScheme(
2675 TPMI_ALG_ASYM_SCHEME scheme
2676 )
2677 {
2678 BOOL isSignScheme = FALSE; 2679
2680 switch(scheme)
2681 {
2682 #ifdef TPM_ALG_RSA
2683 // If RSA is implemented, then both signing schemes are required 2684 case TPM_ALG_RSASSA:
2685 case TPM_ALG_RSAPSS:
2686 isSignScheme = TRUE;
2687 break;
2688 #endif //TPM_ALG_RSA
2689
2690 #ifdef TPM_ALG_ECC
2691 // If ECC is implemented ECDSA is required 2692 case TPM_ALG_ECDSA:
2693 #ifdef TPM_ALG_ECDAA
2694 // ECDAA is optional 2695 case TPM_ALG_ECDAA:
2696 #endif
2697 #ifdef TPM_ALG_ECSCHNORR
2698 // Schnorr is also optional 2699 case TPM_ALG_ECSCHNORR:
2700 #endif
2701 #ifdef TPM_ALG_SM2
2702 case TPM_ALG_SM2:
2703 #endif
2704 isSignScheme = TRUE;
2705 break;
2706 #endif //TPM_ALG_ECC
2707 default:
2708 break;
2709 }
2710 return isSignScheme;
2711 }
This function indicate if a scheme algorithm is a decrypt algorithm.
2712 BOOL
2713 CryptIsDecryptScheme(
2714 TPMI_ALG_ASYM_SCHEME scheme
2715 )
2716 {
2717 BOOL isDecryptScheme = FALSE; 2718
2719 switch(scheme)
2720 {
2721 #ifdef TPM_ALG_RSA
2722 // If RSA is implemented, then both decrypt schemes are required 2723 case TPM_ALG_RSAES:
2724 case TPM_ALG_OAEP:
2725 isDecryptScheme = TRUE;
2726 break;
2727 #endif //TPM_ALG_RSA
2728
2729 #ifdef TPM_ALG_ECC
2730 // If ECC is implemented ECDH is required 2731 case TPM_ALG_ECDH:
2732 #ifdef TPM_ALG_SM2
2733 case TPM_ALG_SM2:
2734 #endif
2735 #ifdef TPM_ALG_ECMQV
2736 case TPM_ALG_ECMQV:
2737 #endif
2738 isDecryptScheme = TRUE;
2739 break;
2740 #endif //TPM_ALG_ECC
2741 default:
2742 break;
2743 }
2744 return isDecryptScheme;
2745 }
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.
Error Returns | Meaning |
TPM_RC_KEY | key referenced by signHandle is not a signing key |
TPM_RC_SCHEME | both scheme and key's default scheme are empty; or scheme is empty while key's default scheme requires explicit input scheme (split signing); or non-empty default key scheme differs from scheme |
2746 TPM_RC
2747 CryptSelectSignScheme(
2748 TPMI_DH_OBJECT signHandle, // IN: handle of signing key 2749 TPMT_SIG_SCHEME *scheme // IN/OUT: signing scheme 2750 )
2751 {
2752 OBJECT *signObject;
2753 TPMT_SIG_SCHEME *objectScheme;
2754 TPMT_PUBLIC *publicArea;
2755 TPM_RC result = TPM_RC_SUCCESS;
2756
2757 // If the signHandle is TPM_RH_NULL, then the NULL scheme is used, regardless 2758 // of the setting of scheme
2759 if(signHandle == TPM_RH_NULL) 2760 {
2761 scheme->scheme = TPM_ALG_NULL;
2762 scheme->details.any.hashAlg = TPM_ALG_NULL; 2763 }
2764 else
2765 {
2766 // sign handle is not NULL so...
2767 // Get sign object pointer
2768 signObject = ObjectGet(signHandle);
2769 publicArea = &signObject->publicArea; 2770
2771 // is this a signing key?
2772 if(!publicArea->objectAttributes.sign) 2773 result = TPM_RC_KEY;
2774 else
2775 {
2776 // "parms" defined to avoid long code lines.
2777 TPMU_PUBLIC_PARMS *parms = &publicArea->parameters;
2778 if(CryptIsAsymAlgorithm(publicArea->type))
2779 objectScheme = (TPMT_SIG_SCHEME *)&parms->asymDetail.scheme; 2780 else
2781 objectScheme = (TPMT_SIG_SCHEME *)&parms->keyedHashDetail.scheme; 2782
2783 // If the object doesn't have a default scheme, then use the 2784 // input scheme.
2785 if(objectScheme->scheme == TPM_ALG_NULL)
2786 {
2787 // Input and default can't both be NULL
2788 if(scheme->scheme == TPM_ALG_NULL) 2789 result = TPM_RC_SCHEME;
2790
2791 // Assume that the scheme is compatible with the key. If not,
2792 // we will generate an error in the signing operation. 2793
2794 }
2795 else if(scheme->scheme == TPM_ALG_NULL)
2796 {
2797 // input scheme is NULL so use default 2798
2799 // First, check to see if the default requires that the caller
2800 // provided scheme data
2801 if(CryptIsSplitSign(objectScheme->scheme)) 2802 result = TPM_RC_SCHEME;
2803 | else | ||
2804 | { | ||
2805 | scheme->scheme = objectScheme->scheme; | ||
2806 | scheme->details.any.hashAlg | ||
2807 | = objectScheme->details.any.hashAlg; | ||
2808 | } | ||
2809 | } | ||
2810 | else | ||
2811 | { | ||
2812 | // Both input and object have scheme selectors | ||
2813 | // If the scheme and the hash are not the same then... | ||
2814 | if( objectScheme->scheme != scheme->scheme | ||
2815 | || ( objectScheme->details.any.hashAlg | ||
2816 | != scheme->details.any.hashAlg)) | ||
2817 | result = TPM_RC_SCHEME; | ||
2818 | } | ||
2819 | } | ||
2820 | |||
2821 | } | ||
2822 | return result; | ||
2823 | } |
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.
Error Returns | Meaning |
TPM_RC_SCHEME | signScheme is not compatible with the signing key type |
TPM_RC_VALUE | digest value is greater than the modulus of signHandle or size of hashData does not match hash algorithm insignScheme (for an RSA key); invalid commit status or failed to generate r value (for an ECC key) |
2824 TPM_RC
2825 CryptSign(
2826 TPMI_DH_OBJECT signHandle, // IN: The handle of sign key 2827 TPMT_SIG_SCHEME *signScheme, // IN: sign scheme.
2828 TPM2B_DIGEST *digest, // IN: The digest being signed 2829 TPMT_SIGNATURE *signature // OUT: signature
2830 )
2831 {
2832 OBJECT *signKey = ObjectGet(signHandle);
2833 TPM_RC result = TPM_RC_SCHEME;
2834
2835 // check if input handle is a sign key
2836 pAssert(signKey->publicArea.objectAttributes.sign == SET); 2837
2838 // Must have the private portion loaded. This check is made during 2839 // authorization.
2840 pAssert(signKey->attributes.publicOnly == CLEAR); 2841
2842 // Initialize signature scheme
2843 signature->sigAlg = signScheme->scheme; 2844
2845 // If the signature algorithm is TPM_ALG_NULL, then we are done 2846 if(signature->sigAlg == TPM_ALG_NULL)
2847 return TPM_RC_SUCCESS;
2848
2849 // All the schemes other than TPM_ALG_NULL have a hash algorithm
2850 TEST_HASH(signScheme->details.any.hashAlg);
2851
2852 // Initialize signature hash
2853 // Note: need to do the check for alg null first because the null scheme 2854 // doesn't have a hashAlg member.
2855 signature->signature.any.hashAlg = signScheme->details.any.hashAlg; 2856
2857 // perform sign operation based on different key type 2858 switch (signKey->publicArea.type)
2859 {
2860
2861 #ifdef TPM_ALG_RSA
2862 case TPM_ALG_RSA:
2863 result = CryptSignRSA(signKey, signScheme, digest, signature); 2864 break;
2865 #endif //TPM_ALG_RSA
2866
2867 #ifdef TPM_ALG_ECC
2868 case TPM_ALG_ECC:
2869 result = CryptSignECC(signKey, signScheme, digest, signature); 2870 break;
2871 #endif //TPM_ALG_ECC
2872 case TPM_ALG_KEYEDHASH:
2873 result = CryptSignHMAC(signKey, signScheme, digest, signature); 2874 break;
2875 default:
2876 break;
2877 | } | |
2878 | ||
2879 | return result; | |
2880 | } |
This function is used to verify a signature. It is called by TPM2_VerifySignature() and TPM2_PolicySigned().
Since this operation only requires use of a public key, no consistency checks are necessary for the key to signature type because a caller can load any public key that they like with any scheme that they like. This routine simply makes sure that the signature is correct, whatever the type.
This function requires that auth is not a NULL pointer.
Error Returns | Meaning |
TPM_RC_SIGNATURE | the signature is not genuine |
TPM_RC_SCHEME | the scheme is not supported |
TPM_RC_HANDLE | an HMAC key was selected but the private part of the key is not loaded |
2881 TPM_RC
2882 CryptVerifySignature(
2883 TPMI_DH_OBJECT keyHandle, // IN: The handle of sign key 2884 TPM2B_DIGEST *digest, // IN: The digest being validated 2885 TPMT_SIGNATURE *signature // IN: signature
2886 )
2887 {
2888 // NOTE: ObjectGet will either return a pointer to a loaded object or
2889 // will assert. It will never return a non-valid value. This makes it save 2890 // to initialize 'publicArea' with the return value from ObjectGet() without 2891 // checking it first.
2892 OBJECT *authObject = ObjectGet(keyHandle); 2893 TPMT_PUBLIC *publicArea = &authObject->publicArea;
2894 TPM_RC result = TPM_RC_SCHEME;
2895
2896 // The input unmarshaling should prevent any input signature from being 2897 // a NULL signature, but just in case
2898 if(signature->sigAlg == TPM_ALG_NULL) 2899 return TPM_RC_SIGNATURE;
2900
2901 switch (publicArea->type)
2902 {
2903
2904 #ifdef TPM_ALG_RSA
2905 case TPM_ALG_RSA:
2906 result = CryptRSAVerifySignature(authObject, digest, signature); 2907 break;
2908 #endif //TPM_ALG_RSA
2909
2910 #ifdef TPM_ALG_ECC
2911 case TPM_ALG_ECC:
2912 result = CryptECCVerifySignature(authObject, digest, signature); 2913 break;
2914
2915 #endif // TPM_ALG_ECC
2916
2917 case TPM_ALG_KEYEDHASH:
2918 if(authObject->attributes.publicOnly) 2919 result = TPM_RCS_HANDLE;
2920 else
2921 result = CryptHMACVerifySignature(authObject, digest, signature); 2922 break;
2923
2924 default:
2925 break;
2926 }
2927 return result;
2928
2929 }
This function interfaces to the math library for large number divide.
Error Returns | Meaning |
TPM_RC_SIZE | quotient or remainder is too small to receive the result |
2930 | TPM_RC | |||
2931 | CryptDivide( | |||
2932 | TPM2B | *numerator, | // | IN: numerator |
2933 | TPM2B | *denominator, | // | IN: denominator |
2934 | TPM2B | *quotient, | // | OUT: quotient = numerator / denominator. |
2935 | TPM2B | *remainder | // | OUT: numerator mod denominator. |
2936 | ) | |||
2937 | { | |||
2938 | pAssert( numerator != NULL | && denominator!= NULL | ||
2939 | && (quotient != NULL | || remainder != NULL) | ||
2940 | ); | |||
2941 | // assume denominator is not | 0 | ||
2942 | pAssert(denominator->size != | 0); | ||
2943 |
2944 return TranslateCryptErrors(_math Div(numerator,
2945 denominator,
2946 | quotient, | ||
2947 | remainder) | ||
2948 | ); | ||
2949 | } |
This function interfaces to the math library for large number, unsigned compare.
Return Value | Meaning |
1 | if a > b |
0 | if a = b |
-1 | if a < b |
2950 | LIB_EXPORT int | ||||
2951 | CryptCompare( | ||||
2952 | const UINT32 | aSize, | // | IN: | size of a |
2953 | const BYTE | *a, | // | IN: | a buffer |
2954 | const UINT32 | bSize, | // | IN: | size of b |
2955 | const BYTE | *b | // | IN: | b buffer |
2956 | ) | ||||
2957 | { |
2958 return _math uComp(aSize, a, bSize, b); 2959 }
This function interfaces to the math library for large number, signed compare.
Return Value | Meaning |
1 | if a > b |
0 | if a = b |
-1 | if a < b |
2960 int
2961 CryptCompareSigned(
2962 UINT32 aSize, // IN: size of a 2963 BYTE *a, // IN: a buffer 2964 UINT32 bSize, // IN: size of b 2965 BYTE *b // IN: b buffer 2966 )
2967 {
2968 return _math Comp(aSize, a, bSize, b); 2969 }
This function returns the results of a self-test function.
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().
2970 | TPM_RC | ||
2971 | CryptGetTestResult( | ||
2972 | TPM2B_MAX_BUFFER | *outData | // OUT: test result data |
2973 | ) | |
2974 | { | |
2975 | outData->t.size = 0; | |
2976 | return TPM_RC_SUCCESS; | |
2977 | } |
This function returns the list of implemented ECC curves.
Return Value | Meaning |
YES | if no more ECC curve is available |
NO | if there are more ECC curves not reported |
2978 | #ifdef TPM_ALG_ECC //% 5 | |
2979 | TPMI_YES_NO | |
2980 | CryptCapGetECCCurve( | |
2981 | TPM_ECC_CURVE curveID, // IN: the starting ECC curve | |
2982 | UINT32 maxCount, // IN: count of returned curve | |
2983 | TPML_ECC_CURVE *curveList // OUT: ECC curve list | |
2984 | ) | |
2985 | { | |
2986 | TPMI_YES_NO more = NO; | |
2987 | UINT16 i; | |
2988 | UINT32 count = _cpri EccGetCurveCount(); | |
2989 | TPM_ECC_CURVE curve; | |
2990 | ||
2991 | // Initialize output property list | |
2992 | curveList->count = 0; | |
2993 | ||
2994 | // The maximum count of curves we may return is MAX_ECC_CURVES | |
2995 | if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES; | |
2996 | ||
2997 | // Scan the eccCurveValues array | |
2998 | for(i = 0; i < count; i++) | |
2999 | { | |
3000 | curve = _cpri GetCurveIdByIndex(i); | |
3001 | // If curveID is less than the starting curveID, skip it | |
3002 | if(curve < curveID) | |
3003 | continue; | |
3004 | ||
3005 | if(curveList->count < maxCount) | |
3006 | { | |
3007 | // If we have not filled up the return list, add more curves | to |
3008 | // it | |
3009 | curveList->eccCurves[curveList->count] = curve; | |
3010 | curveList->count++; | |
3011 | } | |
3012 | else | |
3013 | { | |
3014 | // If the return list is full but we still have curves | |
3015 | // available, report this and stop iterating | |
3016 | more = YES; | |
3017 | break; | |
3018 | } | |
3019 | ||
3020 | } | |
3021 | ||
3022 | return more; | |
3023 |
3024 }
This function returns the number of ECC curves supported by the TPM.
3025 UINT32
3026 CryptCapGetEccCurveNumber(
3027 void
3028 )
3029 {
3030 // There is an array that holds the curve data. Its size divided by the 3031 // size of an entry is the number of values in the table.
3032 return _cpri EccGetCurveCount();
3033 }
3034 #endif //TPM_ALG_ECC //% 5
This function validates that the public key size values are consistent for an asymmetric key.
NOTE: This is not a comprehensive test of the public key.
Return Value | Meaning |
TRUE | sizes are consistent |
FALSE | sizes are not consistent |
3035 | BOOL | |
3036 | CryptAreKeySizesConsistent( | |
3037 | TPMT_PUBLIC *publicArea | // IN: the public area to check |
3038 | ) | |
3039 | { | |
3040 | BOOL consistent | = FALSE; |
3041 | ||
3042 | switch (publicArea->type) | |
3043 | { | |
3044 | #ifdef TPM_ALG_RSA | |
3045 | case TPM_ALG_RSA: | |
3046 | // The key size in | bits is filtered by the unmarshaling |
3047 | consistent = ( | ((publicArea->parameters.rsaDetail.keyBits+7)/8) |
3048 | == | publicArea->unique.rsa.t.size); |
3049 | break; | |
3050 | #endif //TPM_ALG_RSA | |
3051 | ||
3052 | #ifdef TPM_ALG_ECC | |
3053 | case TPM_ALG_ECC: | |
3054 | { | |
3055 | UINT16 | keySizeInBytes; |
3056 | TPM_ECC_CURVE | curveId = publicArea->parameters.eccDetail.curveID; |
3057 | ||
3058 | keySizeInBytes | = CryptEccGetKeySizeInBytes(curveId); |
3059 | ||
3060 | consistent = | keySizeInBytes > 0 |
3061 | && | publicArea->unique.ecc.x.t.size <= keySizeInBytes |
3062 | && | publicArea->unique.ecc.y.t.size <= keySizeInBytes; |
3063 | } | |
3064 | break; | |
3065 | #endif //TPM_ALG_ECC | |
3066 | default: | |
3067 | break; |
3068 }
3069
3070 return consistent;
3071 }
This function initializes the bit vector with one bit for each implemented algorithm. This function is called from _TPM_Init(). The vector of implemented algorithms should be generated by the part 2 parser so that the g_implementedAlgorithms vector can be a const. That's not how it is now
3072 void
3073 CryptAlgsSetImplemented(
3074 void
3075 )
3076 {
3077 AlgorithmGetImplementedVector(&g_implementedAlgorithms);
3078 }
This clause contains the functions used for ticket computations.
#include "InternalRoutines.h"
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
Return Value | Meaning |
TRUE | It is safe to produce ticket |
FALSE | It is not safe to produce ticket |
BOOL
TicketIsSafe(
TPM2B *buffer
5 )
6 {
TPM_GENERATED valueToCompare = TPM_GENERATED_VALUE;
BYTE bufferToCompare[sizeof(valueToCompare)];
BYTE *marshalBuffer; 10
// If the buffer size is less than the size of TPM_GENERATED_VALUE, assume
// it is not safe to generate a ticket
if(buffer->size < sizeof(valueToCompare))
return FALSE; 15
16 marshalBuffer = bufferToCompare;
TPM_GENERATED_Marshal(&valueToCompare, &marshalBuffer, NULL);
if(MemoryEqual(buffer->buffer, bufferToCompare, sizeof(valueToCompare)))
return FALSE;
else
return TRUE; 22 }
This function creates a TPMT_TK_VERIFIED ticket.
void
TicketComputeVerified(
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
TPM2B_DIGEST *digest, // IN: digest
TPM2B_NAME *keyName, // IN: name of key that signed the value
TPMT_TK_VERIFIED *ticket // OUT: verified ticket 29 )
30 {
TPM2B_AUTH *proof;
HMAC_STATE hmacState; 33
// Fill in ticket fields
ticket->tag = TPM_ST_VERIFIED;
ticket->hierarchy = hierarchy; 37
// Use the proof value of the hierarchy
proof = HierarchyGetProof(hierarchy); 40
// Start HMAC
ticket->digest.t.size = CryptStartHMAC2B(CONTEXT_INTEGRITY_HASH_ALG,
&proof->b, &hmacState);
44
// add TPM_ST_VERIFIED
CryptUpdateDigestInt(&hmacState, sizeof(TPM_ST), &ticket->tag); 47
// add digest
CryptUpdateDigest2B(&hmacState, &digest->b); 50
// add key name
CryptUpdateDigest2B(&hmacState, &keyName->b); 53
// complete HMAC
CryptCompleteHMAC2B(&hmacState, &ticket->digest.b); 56
57 return; 58 }
This function creates a TPMT_TK_AUTH ticket.
void
TicketComputeAuth(
TPM_ST type, // IN: the type of ticket.
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
UINT64 timeout, // IN: timeout
TPM2B_DIGEST *cpHashA, // IN: input cpHashA
TPM2B_NONCE *policyRef, // IN: input policyRef
TPM2B_NAME *entityName, // IN: name of entity
TPMT_TK_AUTH *ticket // OUT: Created ticket 68 )
69 {
TPM2B_AUTH *proof;
HMAC_STATE hmacState; 72
// Get proper proof
proof = HierarchyGetProof(hierarchy); 75
// Fill in ticket fields
ticket->tag = type;
ticket->hierarchy = hierarchy; 79
// Start HMAC
ticket->digest.t.size = CryptStartHMAC2B(CONTEXT_INTEGRITY_HASH_ALG,
&proof->b, &hmacState);
83
// Adding TPM_ST_AUTH
CryptUpdateDigestInt(&hmacState, sizeof(UINT16), &ticket->tag); 86
// Adding timeout
CryptUpdateDigestInt(&hmacState, sizeof(UINT64), &timeout); 89
// Adding cpHash
CryptUpdateDigest2B(&hmacState, &cpHashA->b); 92
// Adding policyRef
CryptUpdateDigest2B(&hmacState, &policyRef->b); 95
// Adding keyName
CryptUpdateDigest2B(&hmacState, &entityName->b); 98
// Compute HMAC
CryptCompleteHMAC2B(&hmacState, &ticket->digest.b); 101
102 return;
103 }
This function creates a TPMT_TK_HASHCHECK ticket.
void
TicketComputeHashCheck(
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy constant for ticket
TPM_ALG_ID hashAlg, // IN: the hash algorithm used to create
// 'digest'
TPM2B_DIGEST *digest, // IN: input digest
TPMT_TK_HASHCHECK *ticket // OUT: Created ticket
111 )
112 {
TPM2B_AUTH *proof;
HMAC_STATE hmacState; 115
// Get proper proof
proof = HierarchyGetProof(hierarchy); 118
// Fill in ticket fields
ticket->tag = TPM_ST_HASHCHECK;
ticket->hierarchy = hierarchy; 122
ticket->digest.t.size = CryptStartHMAC2B(CONTEXT_INTEGRITY_HASH_ALG,
&proof->b, &hmacState);
125
// Add TPM_ST_HASHCHECK
CryptUpdateDigestInt(&hmacState, sizeof(TPM_ST), &ticket->tag); 128
// Add hash algorithm
CryptUpdateDigestInt(&hmacState, sizeof(hashAlg), &hashAlg); 131
// Add digest
CryptUpdateDigest2B(&hmacState, &digest->b); 134
// Compute HMAC
CryptCompleteHMAC2B(&hmacState, &ticket->digest.b); 137
138 return;
139 }
This function creates a TPMT_TK_CREATION ticket.
void
TicketComputeCreation(
TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy for ticket
TPM2B_NAME *name, // IN: object name
TPM2B_DIGEST *creation, // IN: creation hash
TPMT_TK_CREATION *ticket // OUT: created ticket
146 )
147 {
TPM2B_AUTH *proof;
HMAC_STATE hmacState; 150
// Get proper proof
proof = HierarchyGetProof(hierarchy); 153
// Fill in ticket fields
ticket->tag = TPM_ST_CREATION;
ticket->hierarchy = hierarchy; 157
ticket->digest.t.size = CryptStartHMAC2B(CONTEXT_INTEGRITY_HASH_ALG,
&proof->b, &hmacState);
160
// Add TPM_ST_CREATION
CryptUpdateDigestInt(&hmacState, sizeof(TPM_ST), &ticket->tag); 163
// Add name
CryptUpdateDigest2B(&hmacState, &name->b); 166
// Add creation hash
CryptUpdateDigest2B(&hmacState, &creation->b); 169
// Compute HMAC
CryptCompleteHMAC2B(&hmacState, &ticket->digest.b); 172
173 return;
174 }
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 SET, then the test function should be called.
#include "Global.h"
#include "CryptoEngine.h"
#include "InternalRoutines.h"
#include "AlgorithmCap_fp.h"
Local function to run self-test
static TPM_RC
CryptRunSelfTests(
ALGORITHM_VECTOR *toTest // IN: the vector of the algorithms to test 8 )
9 {
10 TPM_ALG_ID alg; 11
// For each of the algorithms that are in the toTestVecor, need to run a
// test
for(alg = TPM_ALG_FIRST; alg <= TPM_ALG_LAST; alg++) 15 {
16 if(TEST_BIT(alg, *toTest))
17 {
TPM_RC result = CryptTestAlgorithm(alg, toTest);
if(result != TPM_RC_SUCCESS)
return result;
21 }
22 }
23 return TPM_RC_SUCCESS; 24 }
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.
Error Returns | Meaning |
TPM_RC_CANCELED | if the command is canceled |
LIB_EXPORT
TPM_RC
CryptSelfTest(
TPMI_YES_NO fullTest // IN: if full test is required 29 )
30 {
if(g_forceFailureMode)
FAIL(FATAL_ERROR_FORCED); 33
// If the caller requested a full test, then reset the to test vector so that
// all the tests will be run
36 | if(fullTest == YES) | |
37 | { | |
38 | MemoryCopy(g_toTest, | |
39 | g_implementedAlgorithms, | |
40 | sizeof(g_toTest), sizeof(g_toTest)); | |
41 | } | |
42 | return CryptRunSelfTests(&g_toTest); | |
43 | } |
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.
Error Returns | Meaning |
TPM_RC_CANCELED | processing of this command was canceled |
TPM_RC_TESTING | if toTest list is not empty |
TPM_RC_VALUE | an algorithm in the toTest list is not implemented |
TPM_RC
CryptIncrementalSelfTest(
TPML_ALG *toTest, // IN: list of algorithms to be tested
TPML_ALG *toDoList // OUT: list of algorithms needing test 48 )
49 {
ALGORITHM_VECTOR toTestVector = {0};
TPM_ALG_ID alg;
UINT32 i; 53
pAssert(toTest != NULL && toDoList != NULL);
if(toTest->count > 0)
56 {
// Transcribe the toTest list into the toTestVector
for(i = 0; i < toTest->count; i++)
59 {
60 TPM_ALG_ID alg = toTest->algorithms[i]; 61
// make sure that the algorithm value is not out of range
if((alg > TPM_ALG_LAST) || !TEST_BIT(alg, g_implementedAlgorithms))
return TPM_RC_VALUE;
SET_BIT(alg, toTestVector); 66 }
// Run the test
if(CryptRunSelfTests(&toTestVector) == TPM_RC_CANCELED)
return TPM_RC_CANCELED; 70 }
// Fill in the toDoList with the algorithms that are still untested
toDoList->count = 0; 73
for(alg = TPM_ALG_FIRST;
toDoList->count < MAX_ALG_LIST_SIZE && alg <= TPM_ALG_LAST;
alg++)
77 {
if(TEST_BIT(alg, g_toTest))
toDoList->algorithms[toDoList->count++] = alg; 80 }
81 return TPM_RC_SUCCESS;
82 }
This function will initialize the data structures for testing all the algorithms. This should not be called unless CryptAlgsSetImplemented() has been called
void
CryptInitializeToTest(
void
86 )
87 {
MemoryCopy(g_toTest,
g_implementedAlgorithms,
sizeof(g_toTest),
sizeof(g_toTest));
// Setting the algorithm to null causes the test function to just clear
// out any algorithms for which there is no test.
CryptTestAlgorithm(TPM_ALG_ERROR, &g_toTest); 95
96 return; 97 }
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 algorithms 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 TPM_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.
Error Returns | Meaning |
TPM_RC_SUCCESS | test complete |
TPM_RC_CANCELED | test was canceled |
LIB_EXPORT
TPM_RC
CryptTestAlgorithm(
TPM_ALG_ID alg,
ALGORITHM_VECTOR *toTest
103 )
104 {
TPM_RC result = TPM_RC_SUCCESS;
#ifdef SELF_TEST
// This is the function prototype for TestAlgorithms(). It is here and not
// in a _fp.h file to avoid a compiler error when SELF_TEST is not defined and
// AlgorithmTexts.c is not part of the build.
TPM_RC TestAlgorithm(TPM_ALG_ID alg, ALGORITHM_VECTOR *toTest);
result = TestAlgorithm(alg, toTest);
#else
// If this is an attempt to determine the algorithms for which there is a
// self test, pretend that all of them do. We do that by not clearing any
// of the algorithm bits. When/if this function is called to run tests, it
// will over report. This can be changed so that any call to check on which
// algorithms have tests, 'toTest' can be cleared.
if(alg != TPM_ALG_ERROR)
119 {
CLEAR_BIT(alg, g_toTest);
if(toTest != NULL)
CLEAR_BIT(alg, *toTest);
123 }
#endif
return result;
126 }
This header file contains definitions that are derived from the values in the annexes of TPM 2.0 Part 2. This file would change based on the implementation.
The values shown in this version of the file reflect the example settings in TPM 2.0 Part 2.
#ifndef _IMPLEMENTATION_H_
#define _IMPLEMENTATION_H_
#include "BaseTypes.h"
#include "TPMB.h"
#undef TRUE
#undef FALSE
This table is built in to TpmStructures() Change these definitions to turn all algorithms or commands on or off
7 | #define | ALG_YES | YES |
8 | #define | ALG_NO | NO |
9 | #define | CC_YES | YES |
10 | #define | CC_NO | NO |
From TPM 2.0 Part 2: Table 4 - Defines for Logic Values
11 | #define | TRUE | 1 |
12 | #define | FALSE | 0 |
13 | #define | YES | 1 |
14 | #define | NO | 0 |
15 | #define | SET | 1 |
16 | #define | CLEAR | 0 |
From Vendor-Specific: Table 1 - Defines for Processor Values
17 | #define | BIG_ENDIAN_TPM | NO |
18 | #define | LITTLE_ENDIAN_TPM | YES |
19 | #define | NO_AUTO_ALIGN | NO |
From Vendor-Specific: Table 2 - Defines for Implemented Algorithms
20 | #define | ALG_RSA | ALG_YES |
21 | #define | ALG_SHA1 | ALG_YES |
22 | #define | ALG_HMAC | ALG_YES |
23 | #define | ALG_AES | ALG_YES |
24 | #define | ALG_MGF1 | ALG_YES |
25 | #define | ALG_XOR | ALG_YES |
26 | #define | ALG_KEYEDHASH | ALG_YES |
27 | #define | ALG_SHA256 | ALG_YES |
28 | #define | ALG_SHA384 | ALG_YES |
29 | #define | ALG_SHA512 | ALG_NO |
30 | #define | ALG_SM3_256 | ALG_NO |
31 | #define | ALG_SM4 | ALG_NO |
32 | #define | ALG_RSASSA | (ALG_YES*ALG_RSA) |
33 | #define | ALG_RSAES | (ALG_YES*ALG_RSA) |
34 | #define | ALG_RSAPSS | (ALG_YES*ALG_RSA) |
35 | #define | ALG_OAEP | (ALG_YES*ALG_RSA) |
36 | #define | ALG_ECC | ALG_YES |
37 | #define | ALG_ECDH | (ALG_YES*ALG_ECC) |
38 | #define | ALG_ECDSA | (ALG_YES*ALG_ECC) |
39 | #define | ALG_ECDAA | (ALG_YES*ALG_ECC) |
40 | #define | ALG_SM2 | (ALG_YES*ALG_ECC) |
41 | #define | ALG_ECSCHNORR | (ALG_YES*ALG_ECC) |
42 | #define | ALG_ECMQV | (ALG_NO*ALG_ECC) |
43 | #define | ALG_SYMCIPHER | ALG_YES |
44 | #define | ALG_KDF1_SP800_56A | (ALG_YES*ALG_ECC) |
45 | #define | ALG_KDF2 | ALG_NO |
46 | #define | ALG_KDF1_SP800_108 | ALG_YES |
47 | #define | ALG_CTR | ALG_YES |
48 | #define | ALG_OFB | ALG_YES |
49 | #define | ALG_CBC | ALG_YES |
50 | #define | ALG_CFB | ALG_YES |
51 | #define | ALG_ECB | ALG_YES |
From Vendor-Specific: Table 4 - Defines for Key Size Constants
52 | #define | RSA_KEY_SIZES_BITS {1024,2048} |
53 | #define | RSA_KEY_SIZE_BITS_1024 RSA_ALLOWED_KEY_SIZE_1024 |
54 | #define | RSA_KEY_SIZE_BITS_2048 RSA_ALLOWED_KEY_SIZE_2048 |
55 | #define | MAX_RSA_KEY_BITS 2048 |
56 | #define | MAX_RSA_KEY_BYTES 256 |
57 | #define | AES_KEY_SIZES_BITS {128,256} |
58 | #define | AES_KEY_SIZE_BITS_128 AES_ALLOWED_KEY_SIZE_128 |
59 | #define | AES_KEY_SIZE_BITS_256 AES_ALLOWED_KEY_SIZE_256 |
60 | #define | MAX_AES_KEY_BITS 256 |
61 | #define | MAX_AES_KEY_BYTES 32 |
62 | #define | MAX_AES_BLOCK_SIZE_BYTES \ |
63 | MAX(AES_128_BLOCK_SIZE_BYTES, \ | |
64 | MAX(AES_256_BLOCK_SIZE_BYTES, 0)) | |
65 | #define | SM4_KEY_SIZES_BITS {128} |
66 | #define | SM4_KEY_SIZE_BITS_128 SM4_ALLOWED_KEY_SIZE_128 |
67 | #define | MAX_SM4_KEY_BITS 128 |
68 | #define | MAX_SM4_KEY_BYTES 16 |
69 | #define | MAX_SM4_BLOCK_SIZE_BYTES \ |
70 | MAX(SM4_128_BLOCK_SIZE_BYTES, 0) | |
71 | #define | CAMELLIA_KEY_SIZES_BITS {128} |
72 | #define | CAMELLIA_KEY_SIZE_BITS_128 CAMELLIA_ALLOWED_KEY_SIZE_128 |
73 | #define | MAX_CAMELLIA_KEY_BITS 128 |
74 | #define | MAX_CAMELLIA_KEY_BYTES 16 |
75 | #define | MAX_CAMELLIA_BLOCK_SIZE_BYTES \ |
76 | MAX(CAMELLIA_128_BLOCK_SIZE_BYTES, 0) |
From Vendor-Specific: Table 5 - Defines for Implemented Curves
#define ECC_NIST_P256 YES
#define ECC_NIST_P384 YES
#define ECC_BN_P256 YES
#define ECC_CURVES {\
TPM_ECC_BN_P256, TPM_ECC_NIST_P256, TPM_ECC_NIST_P384}
#define ECC_KEY_SIZES_BITS {256, 384}
#define ECC_KEY_SIZE_BITS_256
#define ECC_KEY_SIZE_BITS_384
#define MAX_ECC_KEY_BITS 384
#define MAX_ECC_KEY_BYTES 48
From Vendor-Specific: Table 6 - Defines for Implemented Commands
87 | #define | CC_ActivateCredential | CC_YES |
88 | #define | CC_Certify | CC_YES |
89 | #define | CC_CertifyCreation | CC_YES |
90 | #define | CC_ChangeEPS | CC_YES |
91 | #define | CC_ChangePPS | CC_YES |
92 | #define | CC_Clear | CC_YES |
93 | #define | CC_ClearControl | CC_YES |
94 | #define | CC_ClockRateAdjust | CC_YES |
95 | #define | CC_ClockSet | CC_YES |
96 | #define | CC_Commit | (CC_YES*ALG_ECC) |
97 | #define | CC_ContextLoad | CC_YES |
98 | #define | CC_ContextSave | CC_YES |
99 | #define | CC_Create | CC_YES |
100 | #define | CC_CreatePrimary | CC_YES |
101 | #define | CC_DictionaryAttackLockReset | CC_YES |
102 | #define | CC_DictionaryAttackParameters | CC_YES |
103 | #define | CC_Duplicate | CC_YES |
104 | #define | CC_ECC_Parameters | (CC_YES*ALG_ECC) |
105 | #define | CC_ECDH_KeyGen | (CC_YES*ALG_ECC) |
106 | #define | CC_ECDH_ZGen | (CC_YES*ALG_ECC) |
107 | #define | CC_EncryptDecrypt | CC_YES |
108 | #define | CC_EventSequenceComplete | CC_YES |
109 | #define | CC_EvictControl | CC_YES |
110 | #define | CC_FieldUpgradeData | CC_NO |
111 | #define | CC_FieldUpgradeStart | CC_NO |
112 | #define | CC_FirmwareRead | CC_NO |
113 | #define | CC_FlushContext | CC_YES |
114 | #define | CC_GetCapability | CC_YES |
115 | #define | CC_GetCommandAuditDigest | CC_YES |
116 | #define | CC_GetRandom | CC_YES |
117 | #define | CC_GetSessionAuditDigest | CC_YES |
118 | #define | CC_GetTestResult | CC_YES |
119 | #define | CC_GetTime | CC_YES |
120 | #define | CC_Hash | CC_YES |
121 | #define | CC_HashSequenceStart | CC_YES |
122 | #define | CC_HierarchyChangeAuth | CC_YES |
123 | #define | CC_HierarchyControl | CC_YES |
124 | #define | CC_HMAC | CC_YES |
125 | #define | CC_HMAC_Start | CC_YES |
126 | #define | CC_Import | CC_YES |
127 | #define | CC_IncrementalSelfTest | CC_YES |
128 | #define | CC_Load | CC_YES |
129 | #define | CC_LoadExternal | CC_YES |
130 | #define | CC_MakeCredential | CC_YES |
131 | #define | CC_NV_Certify | CC_YES |
132 | #define | CC_NV_ChangeAuth | CC_YES |
133 | #define | CC_NV_DefineSpace | CC_YES |
134 | #define | CC_NV_Extend | CC_YES |
135 | #define | CC_NV_GlobalWriteLock | CC_YES |
136 | #define | CC_NV_Increment | CC_YES |
137 | #define | CC_NV_Read | CC_YES |
138 | #define | CC_NV_ReadLock | CC_YES |
139 | #define | CC_NV_ReadPublic | CC_YES |
140 | #define | CC_NV_SetBits | CC_YES |
141 | #define | CC_NV_UndefineSpace | CC_YES |
142 | #define | CC_NV_UndefineSpaceSpecial | CC_YES |
143 | #define | CC_NV_Write | CC_YES |
144 | #define | CC_NV_WriteLock | CC_YES |
145 | #define | CC_ObjectChangeAuth | CC_YES |
146 | #define | CC_PCR_Allocate | CC_YES |
147 | #define | CC_PCR_Event | CC_YES |
148 | #define | CC_PCR_Extend | CC_YES |
149 | #define | CC_PCR_Read | CC_YES |
150 | #define | CC_PCR_Reset | CC_YES |
151 | #define | CC_PCR_SetAuthPolicy | CC_YES |
152 | #define | CC_PCR_SetAuthValue | CC_YES |
153 | #define | CC_PolicyAuthorize | CC_YES |
154 | #define | CC_PolicyAuthValue | CC_YES |
155 | #define | CC_PolicyCommandCode | CC_YES |
156 | #define | CC_PolicyCounterTimer | CC_YES |
157 | #define | CC_PolicyCpHash | CC_YES |
158 | #define | CC_PolicyDuplicationSelect | CC_YES |
159 | #define | CC_PolicyGetDigest | CC_YES |
160 | #define | CC_PolicyLocality | CC_YES |
161 | #define | CC_PolicyNameHash | CC_YES |
162 | #define | CC_PolicyNV | CC_YES |
163 | #define | CC_PolicyOR | CC_YES |
164 | #define | CC_PolicyPassword | CC_YES |
165 | #define | CC_PolicyPCR | CC_YES |
166 | #define | CC_PolicyPhysicalPresence | CC_YES |
167 | #define | CC_PolicyRestart | CC_YES |
168 | #define | CC_PolicySecret | CC_YES |
169 | #define | CC_PolicySigned | CC_YES |
170 | #define | CC_PolicyTicket | CC_YES |
171 | #define | CC_PP_Commands | CC_YES |
172 | #define | CC_Quote | CC_YES |
173 | #define | CC_ReadClock | CC_YES |
174 | #define | CC_ReadPublic | CC_YES |
175 | #define | CC_Rewrap | CC_YES |
176 | #define | CC_RSA_Decrypt | (CC_YES*ALG_RSA) |
177 | #define | CC_RSA_Encrypt | (CC_YES*ALG_RSA) |
178 | #define | CC_SelfTest | CC_YES |
179 | #define | CC_SequenceComplete | CC_YES |
180 | #define | CC_SequenceUpdate | CC_YES |
181 | #define | CC_SetAlgorithmSet | CC_YES |
182 | #define | CC_SetCommandCodeAuditStatus | CC_YES |
183 | #define | CC_SetPrimaryPolicy | CC_YES |
184 | #define | CC_Shutdown | CC_YES |
185 | #define | CC_Sign | CC_YES |
186 | #define | CC_StartAuthSession | CC_YES |
187 | #define | CC_Startup | CC_YES |
188 | #define | CC_StirRandom | CC_YES |
189 | #define | CC_TestParms | CC_YES |
190 | #define | CC_Unseal | CC_YES |
191 | #define | CC_VerifySignature | CC_YES |
192 | #define | CC_ZGen_2Phase | (CC_YES*ALG_ECC) |
193 | #define | CC_EC_Ephemeral | (CC_YES*ALG_ECC) |
194 | #define | CC_PolicyNvWritten | CC_YES |
From Vendor-Specific: Table 7 - Defines for Implementation Values
195 | #define | FIELD_UPGRADE_IMPLEMENTED | NO |
196 | #define | BSIZE | UINT16 |
197 | #define | BUFFER_ALIGNMENT | 4 |
198 | #define | IMPLEMENTATION_PCR | 24 |
199 | #define | PLATFORM_PCR | 24 |
200 | #define | DRTM_PCR | 17 |
201 | #define | HCRTM_PCR | 0 |
202 | #define | NUM_LOCALITIES | 5 |
203 | #define | MAX_HANDLE_NUM | 3 |
204 | #define | MAX_ACTIVE_SESSIONS | 64 |
205 | #define | CONTEXT_SLOT | UINT16 |
206 | #define | CONTEXT_COUNTER | UINT64 |
207 | #define | MAX_LOADED_SESSIONS | 3 |
208 | #define | MAX_SESSION_NUM | 3 |
209 | #define | MAX_LOADED_OBJECTS | 3 |
210 | #define | MIN_EVICT_OBJECTS | 2 |
211 | #define | PCR_SELECT_MIN | ((PLATFORM_PCR+7)/8) |
212 | #define | PCR_SELECT_MAX | ((IMPLEMENTATION_PCR+7)/8) |
213 | #define | NUM_POLICY_PCR_GROUP | 1 |
214 | #define | NUM_AUTHVALUE_PCR_GROUP | 1 |
215 | #define | MAX_CONTEXT_SIZE | 2048 |
216 | #define | MAX_DIGEST_BUFFER | 1024 |
217 | #define | MAX_NV_INDEX_SIZE | 2048 |
218 | #define | MAX_NV_BUFFER_SIZE | 1024 |
219 | #define | MAX_CAP_BUFFER | 1024 |
220 | #define | NV_MEMORY_SIZE | 16384 |
221 | #define | NUM_STATIC_PCR | 16 |
222 | #define | MAX_ALG_LIST_SIZE | 64 |
223 | #define | TIMER_PRESCALE | 100000 |
224 | #define | PRIMARY_SEED_SIZE | 32 |
225 | #define | CONTEXT_ENCRYPT_ALG | TPM_ALG_AES |
226 | #define | CONTEXT_ENCRYPT_KEY_BITS | MAX_SYM_KEY_BITS |
227 | #define | CONTEXT_ENCRYPT_KEY_BYTES | ((CONTEXT_ENCRYPT_KEY_BITS+7)/8) |
228 | #define | CONTEXT_INTEGRITY_HASH_ALG | TPM_ALG_SHA256 |
229 | #define | CONTEXT_INTEGRITY_HASH_SIZE | SHA256_DIGEST_SIZE |
230 | #define | PROOF_SIZE | CONTEXT_INTEGRITY_HASH_SIZE |
231 | #define | NV_CLOCK_UPDATE_INTERVAL | 12 |
232 | #define | NUM_POLICY_PCR | 1 |
233 | #define | MAX_COMMAND_SIZE | 4096 |
234 | #define | MAX_RESPONSE_SIZE | 4096 |
235 | #define | ORDERLY_BITS | 8 |
236 | #define | MAX_ORDERLY_COUNT | ((1<<ORDERLY_BITS)-1) |
237 | #define | ALG_ID_FIRST | TPM_ALG_FIRST |
238 | #define | ALG_ID_LAST | TPM_ALG_LAST |
239 | #define | MAX_SYM_DATA | 128 |
240 | #define | MAX_RNG_ENTROPY_SIZE | 64 |
241 | #define | RAM_INDEX_SPACE | 512 |
242 | #define | RSA_DEFAULT_PUBLIC_EXPONENT | 0x00010001 |
243 | #define | ENABLE_PCR_NO_INCREMENT | YES |
244 | #define | CRT_FORMAT_RSA | YES |
245 | #define | PRIVATE_VENDOR_SPECIFIC_BYTES | \ |
((MAX_RSA_KEY_BYTES/2)*(3+CRT_FORMAT_RSA*2))
From TCG Algorithm Registry: Table 2 - Definition of TPM_ALG_ID Constants
typedef UINT16 TPM_ALG_ID;
#define TPM_ALG_ERROR (TPM_ALG_ID)(0x0000)
#define ALG_ERROR_VALUE 0x0000
#if defined ALG_RSA && ALG_RSA == YES
#define TPM_ALG_RSA (TPM_ALG_ID)(0x0001)
#endif
#define ALG_RSA_VALUE 0x0001
#if defined ALG_SHA && ALG_SHA == YES
#define TPM_ALG_SHA (TPM_ALG_ID)(0x0004)
#endif
#define ALG_SHA_VALUE 0x0004
#if defined ALG_SHA1 && ALG_SHA1 == YES
#define TPM_ALG_SHA1 (TPM_ALG_ID)(0x0004)
#endif
#define ALG_SHA1_VALUE 0x0004
#if defined ALG_HMAC && ALG_HMAC == YES
#define TPM_ALG_HMAC (TPM_ALG_ID)(0x0005)
#endif
#define ALG_HMAC_VALUE 0x0005
#if defined ALG_AES && ALG_AES == YES
#define TPM_ALG_AES (TPM_ALG_ID)(0x0006)
#endif
#define ALG_AES_VALUE 0x0006
#if defined ALG_MGF1 && ALG_MGF1 == YES
#define TPM_ALG_MGF1 (TPM_ALG_ID)(0x0007)
#endif
#define ALG_MGF1_VALUE 0x0007
#if defined ALG_KEYEDHASH && ALG_KEYEDHASH == YES
#define TPM_ALG_KEYEDHASH (TPM_ALG_ID)(0x0008)
#endif
#define ALG_KEYEDHASH_VALUE 0x0008
#if defined ALG_XOR && ALG_XOR == YES
#define TPM_ALG_XOR (TPM_ALG_ID)(0x000A)
#endif
#define ALG_XOR_VALUE 0x000A
#if defined ALG_SHA256 && ALG_SHA256 == YES
#define TPM_ALG_SHA256 (TPM_ALG_ID)(0x000B)
#endif
#define ALG_SHA256_VALUE 0x000B
#if defined ALG_SHA384 && ALG_SHA384 == YES
#define TPM_ALG_SHA384 (TPM_ALG_ID)(0x000C)
#endif
#define ALG_SHA384_VALUE 0x000C
#if defined ALG_SHA512 && ALG_SHA512 == YES
#define TPM_ALG_SHA512 (TPM_ALG_ID)(0x000D)
#endif
#define ALG_SHA512_VALUE 0x000D
#define TPM_ALG_NULL (TPM_ALG_ID)(0x0010)
#define ALG_NULL_VALUE 0x0010
#if defined ALG_SM3_256 && ALG_SM3_256 == YES
#define TPM_ALG_SM3_256 (TPM_ALG_ID)(0x0012)
#endif
#define ALG_SM3_256_VALUE 0x0012
#if defined ALG_SM4 && ALG_SM4 == YES
#define TPM_ALG_SM4 (TPM_ALG_ID)(0x0013)
#endif
#define ALG_SM4_VALUE 0x0013
#if defined ALG_RSASSA && ALG_RSASSA == YES
#define TPM_ALG_RSASSA (TPM_ALG_ID)(0x0014)
#endif
#define ALG_RSASSA_VALUE 0x0014
#if defined ALG_RSAES && ALG_RSAES == YES
#define TPM_ALG_RSAES (TPM_ALG_ID)(0x0015)
#endif
#define ALG_RSAES_VALUE 0x0015
#if defined ALG_RSAPSS && ALG_RSAPSS == YES
#define TPM_ALG_RSAPSS (TPM_ALG_ID)(0x0016)
#endif
#define ALG_RSAPSS_VALUE 0x0016
#if defined ALG_OAEP && ALG_OAEP == YES
#define TPM_ALG_OAEP (TPM_ALG_ID)(0x0017)
#endif
#define ALG_OAEP_VALUE 0x0017
#if defined ALG_ECDSA && ALG_ECDSA == YES
#define TPM_ALG_ECDSA (TPM_ALG_ID)(0x0018)
#endif
#define ALG_ECDSA_VALUE 0x0018
#if defined ALG_ECDH && ALG_ECDH == YES
#define TPM_ALG_ECDH (TPM_ALG_ID)(0x0019)
#endif
#define ALG_ECDH_VALUE 0x0019
#if defined ALG_ECDAA && ALG_ECDAA == YES
#define TPM_ALG_ECDAA (TPM_ALG_ID)(0x001A)
#endif
#define ALG_ECDAA_VALUE 0x001A
#if defined ALG_SM2 && ALG_SM2 == YES
#define TPM_ALG_SM2 (TPM_ALG_ID)(0x001B)
#endif
#define ALG_SM2_VALUE 0x001B
#if defined ALG_ECSCHNORR && ALG_ECSCHNORR == YES
#define TPM_ALG_ECSCHNORR (TPM_ALG_ID)(0x001C)
#endif
#define ALG_ECSCHNORR_VALUE 0x001C
#if defined ALG_ECMQV && ALG_ECMQV == YES
#define TPM_ALG_ECMQV (TPM_ALG_ID)(0x001D)
#endif
#define ALG_ECMQV_VALUE 0x001D
#if defined ALG_KDF1_SP800_56A && ALG_KDF1_SP800_56A == YES
#define TPM_ALG_KDF1_SP800_56A (TPM_ALG_ID)(0x0020)
#endif
#define ALG_KDF1_SP800_56A_VALUE 0x0020
#if defined ALG_KDF2 && ALG_KDF2 == YES
#define TPM_ALG_KDF2 (TPM_ALG_ID)(0x0021)
#endif
#define ALG_KDF2_VALUE 0x0021
#if defined ALG_KDF1_SP800_108 && ALG_KDF1_SP800_108 == YES
#define TPM_ALG_KDF1_SP800_108 (TPM_ALG_ID)(0x0022)
#endif
#define ALG_KDF1_SP800_108_VALUE 0x0022
#if defined ALG_ECC && ALG_ECC == YES
#define TPM_ALG_ECC (TPM_ALG_ID)(0x0023)
#endif
#define ALG_ECC_VALUE 0x0023
#if defined ALG_SYMCIPHER && ALG_SYMCIPHER == YES
#define TPM_ALG_SYMCIPHER (TPM_ALG_ID)(0x0025)
#endif
#define ALG_SYMCIPHER_VALUE 0x0025
#if defined ALG_CAMELLIA && ALG_CAMELLIA == YES
#define TPM_ALG_CAMELLIA (TPM_ALG_ID)(0x0026)
#endif
#define ALG_CAMELLIA_VALUE 0x0026
#if defined ALG_CTR && ALG_CTR == YES
#define TPM_ALG_CTR (TPM_ALG_ID)(0x0040)
#endif
#define ALG_CTR_VALUE 0x0040
#if defined ALG_OFB && ALG_OFB == YES
#define TPM_ALG_OFB (TPM_ALG_ID)(0x0041)
#endif
#define ALG_OFB_VALUE 0x0041
#if defined ALG_CBC && ALG_CBC == YES
#define TPM_ALG_CBC (TPM_ALG_ID)(0x0042)
#endif
#define ALG_CBC_VALUE 0x0042
#if defined ALG_CFB && ALG_CFB == YES
#define TPM_ALG_CFB (TPM_ALG_ID)(0x0043)
#endif
#define ALG_CFB_VALUE 0x0043
#if defined ALG_ECB && ALG_ECB == YES
#define TPM_ALG_ECB (TPM_ALG_ID)(0x0044)
#endif
#define ALG_ECB_VALUE 0x0044
#define TPM_ALG_FIRST (TPM_ALG_ID)(0x0001)
#define ALG_FIRST_VALUE 0x0001
#define TPM_ALG_LAST (TPM_ALG_ID)(0x0044)
#define ALG_LAST_VALUE 0x0044
From TCG Algorithm Registry: Table 3 - Definition of TPM_ECC_CURVE Constants
392 | typedef | UINT16 | TPM_ECC_CURVE; |
393 | #define | TPM_ECC_NONE | (TPM_ECC_CURVE)(0x0000) |
394 | #define | TPM_ECC_NIST_P192 | (TPM_ECC_CURVE)(0x0001) |
395 | #define | TPM_ECC_NIST_P224 | (TPM_ECC_CURVE)(0x0002) |
396 | #define | TPM_ECC_NIST_P256 | (TPM_ECC_CURVE)(0x0003) |
397 | #define | TPM_ECC_NIST_P384 | (TPM_ECC_CURVE)(0x0004) |
398 | #define | TPM_ECC_NIST_P521 | (TPM_ECC_CURVE)(0x0005) |
399 | #define | TPM_ECC_BN_P256 | (TPM_ECC_CURVE)(0x0010) |
400 | #define | TPM_ECC_BN_P638 | (TPM_ECC_CURVE)(0x0011) |
401 | #define | TPM_ECC_SM2_P256 | (TPM_ECC_CURVE)(0x0020) |
From TCG Algorithm Registry: Table 4 - Defines for NIST_P192 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 5 - Defines for NIST_P224 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 6 - Defines for NIST_P256 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 7 - Defines for NIST_P384 ECC Values Data in CrpiEccData.c From TCG
Algorithm Registry: Table 8 - Defines for NIST_P521 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 9 - Defines for BN_P256 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 10 - Defines for BN_P638 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 11 - Defines for SM2_P256 ECC Values Data in CrpiEccData.c From TCG Algorithm Registry: Table 12 - Defines for SHA1 Hash Values
402 | #define | SHA1_DIGEST_SIZE | 20 |
403 | #define | SHA1_BLOCK_SIZE | 64 |
404 | #define | SHA1_DER_SIZE | 15 |
405 | #define | SHA1_DER | \ |
406 0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14
From TCG Algorithm Registry: Table 13 - Defines for SHA256 Hash Values
407 | #define | SHA256_DIGEST_SIZE | 32 |
408 | #define | SHA256_BLOCK_SIZE | 64 |
409 | #define | SHA256_DER_SIZE | 19 |
410 | #define | SHA256_DER | \ |
411 |
0x30,0x31,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0 x04,0x20
From TCG Algorithm Registry: Table 14 - Defines for SHA384 Hash Values
412 | #define | SHA384_DIGEST_SIZE | 48 |
413 | #define | SHA384_BLOCK_SIZE | 128 |
414 | #define | SHA384_DER_SIZE | 19 |
415 | #define | SHA384_DER | \ |
416 |
0x30,0x41,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0 x04,0x30
From TCG Algorithm Registry: Table 15 - Defines for SHA512 Hash Values
417 | #define | SHA512_DIGEST_SIZE | 64 |
418 | #define | SHA512_BLOCK_SIZE | 128 |
419 | #define | SHA512_DER_SIZE | 19 |
420 | #define | SHA512_DER | \ |
421 |
0x30,0x51,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0 x04,0x40
From TCG Algorithm Registry: Table 16 - Defines for SM3_256 Hash Values
422 | #define | SM3_256_DIGEST_SIZE | 32 |
423 | #define | SM3_256_BLOCK_SIZE | 64 |
424 | #define | SM3_256_DER_SIZE | 18 |
425 | #define | SM3_256_DER | \ |
426 |
0x30,0x30,0x30,0x0C,0x06,0x08,0x2A,0x81,0x1C,0x81,0x45,0x01,0x83,0x11,0x05,0x00,0x04,0
x20
From TCG Algorithm Registry: Table 17 - Defines for AES Symmetric Cipher Algorithm Constants
427 | #define | AES_ALLOWED_KEY_SIZE_128 | YES |
428 | #define | AES_ALLOWED_KEY_SIZE_192 | YES |
429 | #define | AES_ALLOWED_KEY_SIZE_256 | YES |
430 | #define | AES_128_BLOCK_SIZE_BYTES | 16 |
431 | #define | AES_192_BLOCK_SIZE_BYTES | 16 |
432 | #define | AES_256_BLOCK_SIZE_BYTES | 16 |
From TCG Algorithm Registry: Table 18 - Defines for SM4 Symmetric Cipher Algorithm Constants
433 #define SM4_ALLOWED_KEY_SIZE_128 YES
434 #define SM4_128_BLOCK_SIZE_BYTES 16
From TCG Algorithm Registry: Table 19 - Defines for CAMELLIA Symmetric Cipher Algorithm Constants
435 | #define | CAMELLIA_ALLOWED_KEY_SIZE_128 | YES |
436 | #define | CAMELLIA_ALLOWED_KEY_SIZE_192 | YES |
437 | #define | CAMELLIA_ALLOWED_KEY_SIZE_256 | YES |
438 | #define | CAMELLIA_128_BLOCK_SIZE_BYTES | 16 |
439 | #define | CAMELLIA_192_BLOCK_SIZE_BYTES | 16 |
440 | #define | CAMELLIA_256_BLOCK_SIZE_BYTES | 16 |
From TPM 2.0 Part 2: Table 13 - Definition of TPM_CC Constants
typedef UINT32 TPM_CC;
#define TPM_CC_FIRST (TPM_CC)(0x0000011F)
#define TPM_CC_PP_FIRST (TPM_CC)(0x0000011F)
#if defined CC_NV_UndefineSpaceSpecial && CC_NV_UndefineSpaceSpecial == YES
#define TPM_CC_NV_UndefineSpaceSpecial (TPM_CC)(0x0000011F)
#endif
#if defined CC_EvictControl && CC_EvictControl == YES
#define TPM_CC_EvictControl (TPM_CC)(0x00000120)
#endif
#if defined CC_HierarchyControl && CC_HierarchyControl == YES
#define TPM_CC_HierarchyControl (TPM_CC)(0x00000121)
#endif
#if defined CC_NV_UndefineSpace && CC_NV_UndefineSpace == YES
#define TPM_CC_NV_UndefineSpace (TPM_CC)(0x00000122)
#endif
#if defined CC_ChangeEPS && CC_ChangeEPS == YES
#define TPM_CC_ChangeEPS (TPM_CC)(0x00000124)
#endif
#if defined CC_ChangePPS && CC_ChangePPS == YES
#define TPM_CC_ChangePPS (TPM_CC)(0x00000125)
#endif
#if defined CC_Clear && CC_Clear == YES
#define TPM_CC_Clear (TPM_CC)(0x00000126)
#endif
#if defined CC_ClearControl && CC_ClearControl == YES
#define TPM_CC_ClearControl (TPM_CC)(0x00000127)
#endif
#if defined CC_ClockSet && CC_ClockSet == YES
#define TPM_CC_ClockSet (TPM_CC)(0x00000128)
#endif
#if defined CC_HierarchyChangeAuth && CC_HierarchyChangeAuth == YES
#define TPM_CC_HierarchyChangeAuth (TPM_CC)(0x00000129)
#endif
#if defined CC_NV_DefineSpace && CC_NV_DefineSpace == YES
#define TPM_CC_NV_DefineSpace (TPM_CC)(0x0000012A)
#endif
#if defined CC_PCR_Allocate && CC_PCR_Allocate == YES
#define TPM_CC_PCR_Allocate (TPM_CC)(0x0000012B)
#endif
#if defined CC_PCR_SetAuthPolicy && CC_PCR_SetAuthPolicy == YES
#define TPM_CC_PCR_SetAuthPolicy (TPM_CC)(0x0000012C)
#endif
#if defined CC_PP_Commands && CC_PP_Commands == YES
#define TPM_CC_PP_Commands (TPM_CC)(0x0000012D)
#endif
#if defined CC_SetPrimaryPolicy && CC_SetPrimaryPolicy == YES
#define TPM_CC_SetPrimaryPolicy (TPM_CC)(0x0000012E)
#endif
#if defined CC_FieldUpgradeStart && CC_FieldUpgradeStart == YES
#define TPM_CC_FieldUpgradeStart (TPM_CC)(0x0000012F)
#endif
#if defined CC_ClockRateAdjust && CC_ClockRateAdjust == YES
#define TPM_CC_ClockRateAdjust (TPM_CC)(0x00000130)
#endif
#if defined CC_CreatePrimary && CC_CreatePrimary == YES
#define TPM_CC_CreatePrimary (TPM_CC)(0x00000131)
#endif
#if defined CC_NV_GlobalWriteLock && CC_NV_GlobalWriteLock == YES
#define TPM_CC_NV_GlobalWriteLock (TPM_CC)(0x00000132)
#endif
#define TPM_CC_PP_LAST (TPM_CC)(0x00000132)
#if defined CC_GetCommandAuditDigest && CC_GetCommandAuditDigest == YES
#define TPM_CC_GetCommandAuditDigest (TPM_CC)(0x00000133)
#endif
#if defined CC_NV_Increment && CC_NV_Increment == YES
#define TPM_CC_NV_Increment (TPM_CC)(0x00000134)
#endif
#if defined CC_NV_SetBits && CC_NV_SetBits == YES
#define TPM_CC_NV_SetBits (TPM_CC)(0x00000135)
#endif
#if defined CC_NV_Extend && CC_NV_Extend == YES
#define TPM_CC_NV_Extend (TPM_CC)(0x00000136)
#endif
#if defined CC_NV_Write && CC_NV_Write == YES
#define TPM_CC_NV_Write (TPM_CC)(0x00000137)
#endif
#if defined CC_NV_WriteLock && CC_NV_WriteLock == YES
#define TPM_CC_NV_WriteLock (TPM_CC)(0x00000138)
#endif
#if defined CC_DictionaryAttackLockReset && CC_DictionaryAttackLockReset == YES
#define TPM_CC_DictionaryAttackLockReset (TPM_CC)(0x00000139)
#endif
#if defined CC_DictionaryAttackParameters && CC_DictionaryAttackParameters == YES
#define TPM_CC_DictionaryAttackParameters (TPM_CC)(0x0000013A)
#endif
#if defined CC_NV_ChangeAuth && CC_NV_ChangeAuth == YES
#define TPM_CC_NV_ChangeAuth (TPM_CC)(0x0000013B)
#endif
#if defined CC_PCR_Event && CC_PCR_Event == YES
#define TPM_CC_PCR_Event (TPM_CC)(0x0000013C)
#endif
#if defined CC_PCR_Reset && CC_PCR_Reset == YES
#define TPM_CC_PCR_Reset (TPM_CC)(0x0000013D)
#endif
#if defined CC_SequenceComplete && CC_SequenceComplete == YES
#define TPM_CC_SequenceComplete (TPM_CC)(0x0000013E)
#endif
#if defined CC_SetAlgorithmSet && CC_SetAlgorithmSet == YES
#define TPM_CC_SetAlgorithmSet (TPM_CC)(0x0000013F)
#endif
#if defined CC_SetCommandCodeAuditStatus && CC_SetCommandCodeAuditStatus == YES
#define TPM_CC_SetCommandCodeAuditStatus (TPM_CC)(0x00000140)
#endif
#if defined CC_FieldUpgradeData && CC_FieldUpgradeData == YES
#define TPM_CC_FieldUpgradeData (TPM_CC)(0x00000141)
#endif
#if defined CC_IncrementalSelfTest && CC_IncrementalSelfTest == YES
#define TPM_CC_IncrementalSelfTest (TPM_CC)(0x00000142)
#endif
#if defined CC_SelfTest && CC_SelfTest == YES
#define TPM_CC_SelfTest (TPM_CC)(0x00000143)
#endif
#if defined CC_Startup && CC_Startup == YES
#define TPM_CC_Startup (TPM_CC)(0x00000144)
#endif
#if defined CC_Shutdown && CC_Shutdown == YES
#define TPM_CC_Shutdown (TPM_CC)(0x00000145)
559 | #if defined CC_StirRandom && CC_StirRandom == YES | |
560 | #define TPM_CC_StirRandom (TPM_CC)(0x00000146) | |
561 | #endif | |
562 | #if defined CC_ActivateCredential && CC_ActivateCredential == YES | |
563 | #define TPM_CC_ActivateCredential (TPM_CC)(0x00000147) | |
564 | #endif | |
565 | #if defined CC_Certify && CC_Certify == YES | |
566 | #define TPM_CC_Certify (TPM_CC)(0x00000148) | |
567 | #endif | |
568 | #if defined CC_PolicyNV && CC_PolicyNV == YES | |
569 | #define TPM_CC_PolicyNV (TPM_CC)(0x00000149) | |
570 | #endif | |
571 | #if defined CC_CertifyCreation && CC_CertifyCreation == YES | |
572 | #define TPM_CC_CertifyCreation (TPM_CC)(0x0000014A) | |
573 | #endif | |
574 | #if defined CC_Duplicate && CC_Duplicate == YES | |
575 | #define TPM_CC_Duplicate (TPM_CC)(0x0000014B) | |
576 | #endif | |
577 | #if defined CC_GetTime && CC_GetTime == YES | |
578 | #define TPM_CC_GetTime (TPM_CC)(0x0000014C) | |
579 | #endif | |
580 | #if defined CC_GetSessionAuditDigest && CC_GetSessionAuditDigest == | YES |
581 | #define TPM_CC_GetSessionAuditDigest (TPM_CC)(0x0000014D) | |
582 | #endif | |
583 | #if defined CC_NV_Read && CC_NV_Read == YES | |
584 | #define TPM_CC_NV_Read (TPM_CC)(0x0000014E) | |
585 | #endif | |
586 | #if defined CC_NV_ReadLock && CC_NV_ReadLock == YES | |
587 | #define TPM_CC_NV_ReadLock (TPM_CC)(0x0000014F) | |
588 | #endif | |
589 | #if defined CC_ObjectChangeAuth && CC_ObjectChangeAuth == YES | |
590 | #define TPM_CC_ObjectChangeAuth (TPM_CC)(0x00000150) | |
591 | #endif | |
592 | #if defined CC_PolicySecret && CC_PolicySecret == YES | |
593 | #define TPM_CC_PolicySecret (TPM_CC)(0x00000151) | |
594 | #endif | |
595 | #if defined CC_Rewrap && CC_Rewrap == YES | |
596 | #define TPM_CC_Rewrap (TPM_CC)(0x00000152) | |
597 | #endif | |
598 | #if defined CC_Create && CC_Create == YES | |
599 | #define TPM_CC_Create (TPM_CC)(0x00000153) | |
600 | #endif | |
601 | #if defined CC_ECDH_ZGen && CC_ECDH_ZGen == YES | |
602 | #define TPM_CC_ECDH_ZGen (TPM_CC)(0x00000154) | |
603 | #endif | |
604 | #if defined CC_HMAC && CC_HMAC == YES | |
605 | #define TPM_CC_HMAC (TPM_CC)(0x00000155) | |
606 | #endif | |
607 | #if defined CC_Import && CC_Import == YES | |
608 | #define TPM_CC_Import (TPM_CC)(0x00000156) | |
609 | #endif | |
610 | #if defined CC_Load && CC_Load == YES | |
611 | #define TPM_CC_Load (TPM_CC)(0x00000157) | |
612 | #endif | |
613 | #if defined CC_Quote && CC_Quote == YES | |
614 | #define TPM_CC_Quote (TPM_CC)(0x00000158) | |
615 | #endif | |
616 | #if defined CC_RSA_Decrypt && CC_RSA_Decrypt == YES | |
617 | #define TPM_CC_RSA_Decrypt (TPM_CC)(0x00000159) | |
618 | #endif | |
619 | #if defined CC_HMAC_Start && CC_HMAC_Start == YES |
620 #define TPM_CC_HMAC_Start (TPM_CC)(0x0000015B) 621 #endif
622 #if defined CC_SequenceUpdate && CC_SequenceUpdate == YES
623 #define TPM_CC_SequenceUpdate (TPM_CC)(0x0000015C)
625 | #if defined CC_Sign && CC_Sign == YES |
626 | #define TPM_CC_Sign (TPM_CC)(0x0000015D) |
627 | #endif |
628 | #if defined CC_Unseal && CC_Unseal == YES |
629 | #define TPM_CC_Unseal (TPM_CC)(0x0000015E) |
630 | #endif |
631 | #if defined CC_PolicySigned && CC_PolicySigned == YES |
632 | #define TPM_CC_PolicySigned (TPM_CC)(0x00000160) |
633 | #endif |
634 | #if defined CC_ContextLoad && CC_ContextLoad == YES |
635 | #define TPM_CC_ContextLoad (TPM_CC)(0x00000161) |
636 | #endif |
637 | #if defined CC_ContextSave && CC_ContextSave == YES |
638 | #define TPM_CC_ContextSave (TPM_CC)(0x00000162) |
639 | #endif |
640 | #if defined CC_ECDH_KeyGen && CC_ECDH_KeyGen == YES |
641 | #define TPM_CC_ECDH_KeyGen (TPM_CC)(0x00000163) |
642 | #endif |
643 | #if defined CC_EncryptDecrypt && CC_EncryptDecrypt == YES |
644 | #define TPM_CC_EncryptDecrypt (TPM_CC)(0x00000164) |
645 | #endif |
646 | #if defined CC_FlushContext && CC_FlushContext == YES |
647 | #define TPM_CC_FlushContext (TPM_CC)(0x00000165) |
648 | #endif |
649 | #if defined CC_LoadExternal && CC_LoadExternal == YES |
650 | #define TPM_CC_LoadExternal (TPM_CC)(0x00000167) |
651 | #endif |
652 | #if defined CC_MakeCredential && CC_MakeCredential == YES |
653 | #define TPM_CC_MakeCredential (TPM_CC)(0x00000168) |
654 | #endif |
655 | #if defined CC_NV_ReadPublic && CC_NV_ReadPublic == YES |
656 | #define TPM_CC_NV_ReadPublic (TPM_CC)(0x00000169) |
657 | #endif |
658 | #if defined CC_PolicyAuthorize && CC_PolicyAuthorize == YES |
659 | #define TPM_CC_PolicyAuthorize (TPM_CC)(0x0000016A) |
660 | #endif |
661 | #if defined CC_PolicyAuthValue && CC_PolicyAuthValue == YES |
662 | #define TPM_CC_PolicyAuthValue (TPM_CC)(0x0000016B) |
663 | #endif |
664 | #if defined CC_PolicyCommandCode && CC_PolicyCommandCode == YES |
665 | #define TPM_CC_PolicyCommandCode (TPM_CC)(0x0000016C) |
666 | #endif |
667 | #if defined CC_PolicyCounterTimer && CC_PolicyCounterTimer == YES |
668 | #define TPM_CC_PolicyCounterTimer (TPM_CC)(0x0000016D) |
669 | #endif |
670 | #if defined CC_PolicyCpHash && CC_PolicyCpHash == YES |
671 | #define TPM_CC_PolicyCpHash (TPM_CC)(0x0000016E) |
672 | #endif |
673 | #if defined CC_PolicyLocality && CC_PolicyLocality == YES |
674 | #define TPM_CC_PolicyLocality (TPM_CC)(0x0000016F) |
675 | #endif |
676 | #if defined CC_PolicyNameHash && CC_PolicyNameHash == YES |
677 | #define TPM_CC_PolicyNameHash (TPM_CC)(0x00000170) |
678 | #endif |
679 | #if defined CC_PolicyOR && CC_PolicyOR == YES |
680 | #define TPM_CC_PolicyOR (TPM_CC)(0x00000171) |
681 | #endif |
682 | #if defined CC_PolicyTicket && CC_PolicyTicket == YES |
683 | #define TPM_CC_PolicyTicket (TPM_CC)(0x00000172) |
684 | #endif |
685 | #if defined CC_ReadPublic && CC_ReadPublic == YES |
686 | #define TPM_CC_ReadPublic (TPM_CC)(0x00000173) |
687 | #endif |
688 | #if defined CC_RSA_Encrypt && CC_RSA_Encrypt == YES |
689 | #define TPM_CC_RSA_Encrypt (TPM_CC)(0x00000174) |
690 | #endif | |
691 | #if defined CC_StartAuthSession && CC_StartAuthSession == YES | |
692 | #define TPM_CC_StartAuthSession (TPM_CC)(0x00000176) | |
693 | #endif | |
694 | #if defined CC_VerifySignature && CC_VerifySignature == YES | |
695 | #define TPM_CC_VerifySignature (TPM_CC)(0x00000177) | |
696 | #endif | |
697 | #if defined CC_ECC_Parameters && CC_ECC_Parameters == YES | |
698 | #define TPM_CC_ECC_Parameters (TPM_CC)(0x00000178) | |
699 | #endif | |
700 | #if defined CC_FirmwareRead && CC_FirmwareRead == YES | |
701 | #define TPM_CC_FirmwareRead (TPM_CC)(0x00000179) | |
702 | #endif | |
703 | #if defined CC_GetCapability && CC_GetCapability == YES | |
704 | #define TPM_CC_GetCapability (TPM_CC)(0x0000017A) | |
705 | #endif | |
706 | #if defined CC_GetRandom && CC_GetRandom == YES | |
707 | #define TPM_CC_GetRandom (TPM_CC)(0x0000017B) | |
708 | #endif | |
709 | #if defined CC_GetTestResult && CC_GetTestResult == YES | |
710 | #define TPM_CC_GetTestResult (TPM_CC)(0x0000017C) | |
711 | #endif | |
712 | #if defined CC_Hash && CC_Hash == YES | |
713 | #define TPM_CC_Hash (TPM_CC)(0x0000017D) | |
714 | #endif | |
715 | #if defined CC_PCR_Read && CC_PCR_Read == YES | |
716 | #define TPM_CC_PCR_Read (TPM_CC)(0x0000017E) | |
717 | #endif | |
718 | #if defined CC_PolicyPCR && CC_PolicyPCR == YES | |
719 | #define TPM_CC_PolicyPCR (TPM_CC)(0x0000017F) | |
720 | #endif | |
721 | #if defined CC_PolicyRestart && CC_PolicyRestart == YES | |
722 | #define TPM_CC_PolicyRestart (TPM_CC)(0x00000180) | |
723 | #endif | |
724 | #if defined CC_ReadClock && CC_ReadClock == YES | |
725 | #define TPM_CC_ReadClock (TPM_CC)(0x00000181) | |
726 | #endif | |
727 | #if defined CC_PCR_Extend && CC_PCR_Extend == YES | |
728 | #define TPM_CC_PCR_Extend (TPM_CC)(0x00000182) | |
729 | #endif | |
730 | #if defined CC_PCR_SetAuthValue && CC_PCR_SetAuthValue == YES | |
731 | #define TPM_CC_PCR_SetAuthValue (TPM_CC)(0x00000183) | |
732 | #endif | |
733 | #if defined CC_NV_Certify && CC_NV_Certify == YES | |
734 | #define TPM_CC_NV_Certify (TPM_CC)(0x00000184) | |
735 | #endif | |
736 | #if defined CC_EventSequenceComplete && CC_EventSequenceComplete == | YES |
737 | #define TPM_CC_EventSequenceComplete (TPM_CC)(0x00000185) | |
738 | #endif | |
739 | #if defined CC_HashSequenceStart && CC_HashSequenceStart == YES | |
740 | #define TPM_CC_HashSequenceStart (TPM_CC)(0x00000186) | |
741 | #endif |
742 #if defined CC_PolicyPhysicalPresence && CC_PolicyPhysicalPresence == YES 743 #define TPM_CC_PolicyPhysicalPresence (TPM_CC)(0x00000187)
744 #endif
745 #if defined CC_PolicyDuplicationSelect && CC_PolicyDuplicationSelect == YES 746 #define TPM_CC_PolicyDuplicationSelect (TPM_CC)(0x00000188)
747 #endif
748 #if defined CC_PolicyGetDigest && CC_PolicyGetDigest == YES
749 #define TPM_CC_PolicyGetDigest (TPM_CC)(0x00000189) 750 #endif
751 #if defined CC_TestParms && CC_TestParms == YES
752 #define TPM_CC_TestParms (TPM_CC)(0x0000018A) 753 #endif
754 #if defined CC_Commit && CC_Commit == YES
755 #define TPM_CC_Commit (TPM_CC)(0x0000018B)
756 #endif
757 #if defined CC_PolicyPassword && CC_PolicyPassword == YES
758 #define TPM_CC_PolicyPassword (TPM_CC)(0x0000018C) 759 #endif
760 #if defined CC_ZGen_2Phase && CC_ZGen_2Phase == YES
761 #define TPM_CC_ZGen_2Phase (TPM_CC)(0x0000018D) 762 #endif
763 #if defined CC_EC_Ephemeral && CC_EC_Ephemeral == YES
764 #define TPM_CC_EC_Ephemeral (TPM_CC)(0x0000018E) 765 #endif
766 #if defined CC_PolicyNvWritten && CC_PolicyNvWritten == YES
767 #define TPM_CC_PolicyNvWritten (TPM_CC)(0x0000018F) 768 #endif
769 #define TPM_CC_LAST (TPM_CC)(0x0000018F)
770 #ifndef MAX
771 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 772 #endif
#define MAX_HASH_BLOCK_SIZE ( \
MAX(ALG_SHA1 * SHA1_BLOCK_SIZE, \
MAX(ALG_SHA256 * SHA256_BLOCK_SIZE, \
MAX(ALG_SHA384 * SHA384_BLOCK_SIZE, \
MAX(ALG_SM3_256 * SM3_256_BLOCK_SIZE, \
MAX(ALG_SHA512 * SHA512_BLOCK_SIZE, \
779 0 ))))))
#define MAX_DIGEST_SIZE ( \
MAX(ALG_SHA1 * SHA1_DIGEST_SIZE, \
MAX(ALG_SHA256 * SHA256_DIGEST_SIZE, \
MAX(ALG_SHA384 * SHA384_DIGEST_SIZE, \
MAX(ALG_SM3_256 * SM3_256_DIGEST_SIZE, \
MAX(ALG_SHA512 * SHA512_DIGEST_SIZE, \
786 0 ))))))
787 #if MAX_DIGEST_SIZE == 0 || MAX_HASH_BLOCK_SIZE == 0
788 #error "Hash data not valid" 789 #endif
790 #define HASH_COUNT (ALG_SHA1+ALG_SHA256+ALG_SHA384+ALG_SM3_256+ALG_SHA512)
Define the 2B structure that would hold any hash block
791 TPM2B_TYPE(MAX_HASH_BLOCK, MAX_HASH_BLOCK_SIZE);
Folloing typedef is for some old code
792 | typedef | TPM2B_MAX_HASH_BLOCK |
793 | #ifndef | MAX |
794 | #define | MAX(a, b) ((a) > (b) |
795 | #endif | |
796 | #ifndef | ALG_CAMELLIA |
TPM2B_HASH_BLOCK;
? (a) : (b))
# define ALG_CAMELLIA NO
#endif
#ifndef MAX_CAMELLIA_KEY_BITS
# define MAX_CAMELLIA_KEY_BITS 0
# define MAX_CAMELLIA_BLOCK_SIZE_BYTES 0
#endif
#ifndef ALG_SM4
# define ALG_SM4 NO 805 #endif
#ifndef MAX_SM4_KEY_BITS
# define MAX_SM4_KEY_BITS 0
# define MAX_SM4_BLOCK_SIZE_BYTES 0
#endif
#ifndef ALG_AES
# define ALG_AES NO 812 #endif
#ifndef MAX_AES_KEY_BITS
# define MAX_AES_KEY_BITS 0
# define MAX_AES_BLOCK_SIZE_BYTES 0
#endif
#define MAX_SYM_KEY_BITS ( \
MAX(MAX_CAMELLIA_KEY_BITS * ALG_CAMELLIA, \
MAX(MAX_SM4_KEY_BITS * ALG_SM4, \
MAX(MAX_AES_KEY_BITS * ALG_AES, \
821 0))))
822 #define MAX_SYM_KEY_BYTES ((MAX_SYM_KEY_BITS + 7) / 8)
823 #define MAX_SYM_BLOCK_SIZE ( \
824 MAX(MAX_CAMELLIA_BLOCK_SIZE_BYTES * ALG_CAMELLIA, \
825 MAX(MAX_SM4_BLOCK_SIZE_BYTES * ALG_SM4, \
826 MAX(MAX_AES_BLOCK_SIZE_BYTES * ALG_AES, \
827 0))))
828 #if MAX_SYM_KEY_BITS == 0 || MAX_SYM_BLOCK_SIZE == 0
829 # error Bad size for MAX_SYM_KEY_BITS or MAX_SYM_BLOCK_SIZE 830 #endif
Define the 2B structure for a seed
831 TPM2B_TYPE(SEED, PRIMARY_SEED_SIZE);
832 #endif // _IMPLEMENTATION_H_
The files in this annex provide cryptographic support functions for the TPM.
When possible, the functions in these files make calls to functions that are provided by a cryptographic library (for this annex, it is OpenSSL). In many cases, there is a mismatch between the function performed by the cryptographic library and the function needed by the TPM. In those cases, a function is provided in the code in this clause.
There are cases where the cryptographic library could have been used for a specific function but not all functions of the same group. An example is that the OpenSSL version of CFB was not suitable for the requirements of the TPM. Rather than have one symmetric mode be provided in this code with the remaining modes provided by OpenSSL, all the symmetric modes are provided in this code.
The provided cryptographic code is believed to be functionally correct but it might not be conformant with all applicable standards. For example, the RSA key generation schemes produces serviceable RSA keys but the method is not compliant with FIPS 186-3. Still, the implementation meets the major objective of the implementation, which is to demonstrate proper TPM behavior. It is not an objective of this implementation to be submitted for certification.
The big integers passed to/from the function interfaces in the crypto engine are in BYTE buffers that have the same format used in the TPM 2.0 specification that states:
"Integer values are considered to be an array of one or more bytes. The byte at offset zero within the array is the most significant byte of the integer."
This file contains constant definition shared by CryptUtil() and the parts of the Crypto Engine.
#ifndef _CRYPT_PRI_H
#define _CRYPT_PRI_H
#include <stddef.h>
#include "TpmBuildSwitches.h"
#include "BaseTypes.h"
#include "TpmError.h"
#include "swap.h"
#include "Implementation.h"
#include "TPM_types.h"
//#include "TPMB.h"
#include "bool.h"
#include "Platform.h"
#ifndef NULL
#define NULL 0
#endif
typedef UINT16 NUMBYTES; // When a size is a number of bytes
typedef UINT32 NUMDIGITS; // When a size is a number of "digits"
#ifndef MAX
# define MAX(a, b) ((a) > (b) ? (a) : b)
#endif
This is the definition of a bit array with one bit per algorithm
typedef BYTE ALGORITHM_VECTOR[(ALG_LAST_VALUE + 7) / 8];
This structure is used to contain self-test tracking information for the crypto engine. Each of the major modules is given a 32-bit value in which it may maintain its own self test information. The convention for this state is that when all of the bits in this structure are 0, all functions need to be tested.
typedef struct {
UINT32 rng;
UINT32 hash;
UINT32 sym;
#ifdef TPM_ALG_RSA
UINT32 rsa;
#endif
#ifdef TPM_ALG_ECC
UINT32 ecc;
#endif
} CRYPTO_SELF_TEST_STATE;
typedef struct {
const TPM_ALG_ID alg;
const NUMBYTES digestSize;
const NUMBYTES blockSize;
const NUMBYTES derSize;
const BYTE der[20];
} HASH_INFO;
This value will change with each implementation. The value of 16 is used to account for any slop in the context values. 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
40 | #define ALIGNED_SIZE(x, b) ((((x) + (b) - 1) / (b)) * (b)) | |
41 | #define MAX_HASH_STATE_SIZE ((2 * MAX_HASH_BLOCK_SIZE) + 16) | |
42 | #define MAX_HASH_STATE_SIZE_ALIGNED | \ |
43 | ALIGNED_SIZE(MAX_HASH_STATE_SIZE, CRYPTO_ALIGNMENT) | |
This is an byte array that will hold any of the hash contexts. | ||
44 | typedef CRYPTO_ALIGNED BYTE ALIGNED_HASH_STATE[MAX_HASH_STATE_SIZE_ALIGNED]; | |
Macro to align an address to the next higher size | ||
45 | #define AlignPointer(address, align) | \ |
46 | ((((intptr_t)&(address)) + (align - 1)) & ~(align - 1)) | |
Macro to test alignment | ||
47 | #define IsAddressAligned(address, align) | \ |
48 | (((intptr_t)(address) & (align - 1)) == 0) |
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.
49 typedef struct _HASH_STATE 50 {
ALIGNED_HASH_STATE state;
TPM_ALG_ID hashAlg;
} CPRI_HASH_STATE, *PCPRI_HASH_STATE;
extern const HASH_INFO g_hashData[HASH_COUNT + 1];
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. There is a compile-time check to make sure that this is true.
typedef struct {
ALIGNED_HASH_STATE buffer;
TPM_ALG_ID hashAlg;
} EXPORT_HASH_STATE;
typedef enum {
IMPORT_STATE, // Converts externally formatted state to internal
EXPORT_STATE // Converts internal formatted state to external
} IMPORT_EXPORT;
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 GET_PUT enum is used by
_cpri__DrbgGetPutState() to indicate the direction of data flow.
typedef enum {
GET_STATE, // Get the state to save to NV
PUT_STATE // Restore the state from NV
} GET_PUT;
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
#define DRBG_KEY_SIZE_BITS MAX_AES_KEY_BITS
#define DRBG_IV_SIZE_BITS (MAX_AES_BLOCK_SIZE_BYTES * 8)
#define DRBG_ALGORITHM TPM_ALG_AES
#if ((DRBG_KEY_SIZE_BITS % 8) != 0) || ((DRBG_IV_SIZE_BITS % 8) != 0)
#error "Key size and IV for DRBG must be even multiples of 8"
#endif
#if (DRBG_KEY_SIZE_BITS % DRBG_IV_SIZE_BITS) != 0
#error "Key size for DRBG must be even multiple of the cypher block size"
#endif
typedef UINT32 DRBG_SEED[(DRBG_KEY_SIZE_BITS + DRBG_IV_SIZE_BITS) / 32];
typedef struct {
UINT64 reseedCounter;
UINT32 magic;
DRBG_SEED seed; // contains the key and IV for the counter mode DRBG
UINT32 lastValue[4]; // used when the TPM does continuous self-test
// for FIPS compliance of DRBG
} DRBG_STATE, *pDRBG_STATE;
#ifdef TPM_ALG_ECC
This structure replicates the structure definition in TPM_Types.h. It is duplicated to avoid inclusion of all of TPM_Types.h This structure is similar to the RSA_KEY structure below. The purpose of these structures is to reduce the overhead of a function call and to make the code less dependent on key types as much as possible.
typedef struct {
UINT32 curveID; // The curve identifier
TPMS_ECC_POINT *publicPoint; // Pointer to the public point
TPM2B_ECC_PARAMETER *privateKey; // Pointer to the private key
} ECC_KEY;
#endif // TPM_ALG_ECC
#ifdef TPM_ALG_RSA
This structure is a succinct representation of the cryptographic components of an RSA key.
typedef struct {
UINT32 exponent; // The public exponent pointer
TPM2B *publicKey; // Pointer to the public modulus
TPM2B *privateKey; // The private exponent (not a prime)
} RSA_KEY;
#endif // TPM_ALG_RSA
#ifdef TPM_ALG_RSA
# ifdef TPM_ALG_ECC
# if MAX_RSA_KEY_BYTES > MAX_ECC_KEY_BYTES
# define MAX_NUMBER_SIZE MAX_RSA_KEY_BYTES
# else
# define MAX_NUMBER_SIZE MAX_ECC_KEY_BYTES
# endif
# else // RSA but no ECC
# define MAX_NUMBER_SIZE MAX_RSA_KEY_BYTES
# endif
#elif defined TPM_ALG_ECC
# define MAX_NUMBER_SIZE MAX_ECC_KEY_BYTES
#else
# error No assymmetric algorithm implemented.
#endif
typedef INT16 CRYPT_RESULT;
#define CRYPT_RESULT_MIN INT16_MIN
#define CRYPT_RESULT_MAX INT16_MAX
< 0 | recoverable error |
0 | success |
> 0 | command specific return value (generally a digest size) |
116 | #define | CRYPT_FAIL | ((CRYPT_RESULT) | 1) |
117 | #define | CRYPT_SUCCESS | ((CRYPT_RESULT) | 0) |
118 | #define | CRYPT_NO_RESULT | ((CRYPT_RESULT) | -1) |
119 | #define CRYPT_SCHEME ((CRYPT_RESULT) -2) |
120 | #define CRYPT_PARAMETER ((CRYPT_RESULT) -3) |
121 | #define CRYPT_UNDERFLOW ((CRYPT_RESULT) -4) |
122 | #define CRYPT_POINT ((CRYPT_RESULT) -5) |
123 | #define CRYPT_CANCEL ((CRYPT_RESULT) -6) |
124 | typedef UINT64 HASH_CONTEXT[MAX_HASH_STATE_SIZE/sizeof(UINT64)]; |
125 | #include "CpriCryptPri_fp.h" |
126 | #ifdef TPM_ALG_ECC |
127 | # include "CpriDataEcc.h" |
128 | # include "CpriECC_fp.h" |
129 | #endif |
130 | #include "MathFunctions_fp.h" |
131 | #include "CpriRNG_fp.h" |
132 | #include "CpriHash_fp.h" |
133 | #include "CpriSym_fp.h" |
134 | #ifdef TPM_ALG_RSA |
135 | # include "CpriRSA_fp.h" |
136 | #endif |
137 | #endif // !_CRYPT_PRI_H |
This is the header file used by the components of the CryptoEngine(). This file should not be included in any file other than the files in the crypto engine.
Vendors may replace the implementation in this file by a local crypto engine. The implementation in this file is based on OpenSSL() library. Integer format: the big integers passed in/out the function interfaces in this library by a byte buffer (BYTE *) adopt the same format used in TPM 2.0 specification: Integer values are considered to be an array of one or more bytes. The byte at offset zero within the array is the most significant byte of the integer.
#ifndef _OSSL_CRYPTO_ENGINE_H
#define _OSSL_CRYPTO_ENGINE_H
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/ec.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openSSL/ec_lcl.h>
#define CRYPTO_ENGINE
#include "CryptoEngine.h"
#include "CpriMisc_fp.h"
#define MAX_ECC_PARAMETER_BYTES 32
#define MAX_2B_BYTES MAX((MAX_RSA_KEY_BYTES * ALG_RSA), \
MAX((MAX_ECC_PARAMETER_BYTES * ALG_ECC), \
MAX_DIGEST_SIZE))
#define assert2Bsize(a) pAssert((a).size <= sizeof((a).buffer))
#ifdef TPM_ALG_RSA
# ifdef RSA_KEY_SIEVE
# include "RsaKeySieve.h"
# include "RsaKeySieve_fp.h"
# endif
# include "CpriRSA_fp.h"
#endif
This is a structure to hold the parameters for the version of KDFa() used by the CryptoEngine(). This structure allows the state to be passed between multiple functions that use the same pseudo-random sequence.
typedef struct {
CPRI_HASH_STATE iPadCtx;
CPRI_HASH_STATE oPadCtx;
TPM2B *extra;
UINT32 *outer;
TPM_ALG_ID hashAlg;
UINT16 keySizeInBits;
} KDFa_CONTEXT;
#endif // _OSSL_CRYPTO_ENGINE_H
This file contains implementation of some of the big number primitives. This is used in order to reduce the overhead in dealing with data conversions to standard big number format.
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. This library provides functions that are found in typical big number libraries but they are written to handle the canonical data format of the reference TPM.
In some cases, data is converted to a big number format used by a standard library, such as OpenSSL(). This is done when the computations are complex enough warrant conversion. Vendors may replace the implementation in this file with a library that provides equivalent functions. A vendor may also rewrite the TPM code so that it uses a standard big number format instead of the canonical form and use the standard libraries instead of the code in this file.
The implementation in this file makes use of the OpenSSL() library.
Integer format: integers passed through the function interfaces in this library adopt the same format used in TPM 2.0 specification. It defines an integer as "an array of one or more octets with the most significant octet at the lowest index of the array." An additional value is needed to indicate the number of significant bytes.
#include "OsslCryptoEngine.h"
Externally Accessible Functions
This function will normalize the value in a TPM2B. If there are leading bytes of zero, the first non-zero byte is shifted up.
Return Value | Meaning |
0 | no significant bytes, value is zero |
>0 | number of significant bytes |
LIB_EXPORT UINT16
_math Normalize2B(
TPM2B *b // IN/OUT: number to normalize 5 )
6 {
UINT16 from;
UINT16 to;
UINT16 size = b->size; 10
for(from = 0; b->buffer[from] == 0 && from < size; from++);
b->size -= from;
for(to = 0; from < size; to++, from++ )
b->buffer[to] = b->buffer[from];
return b->size; 16 }
This function is used to adjust a TPM2B so that the number has the desired number of bytes. This is accomplished by adding bytes of zero at the start of the number.
Return Value | Meaning |
TRUE | number de-normalized |
FALSE | number already larger than the desired size |
LIB_EXPORT BOOL
_math Denormalize2B(
TPM2B *in, // IN:OUT TPM2B number to de-normalize
UINT32 size // IN: the desired size 21 )
22 {
UINT32 to;
UINT32 from;
// If the current size is greater than the requested size, see if this can be
// normalized to a value smaller than the requested size and then de-normalize
if(in->size > size)
28 {
_math Normalize2B(in);
if(in->size > size)
return FALSE;
32 }
// If the size is already what is requested, leave
if(in->size == size)
return TRUE; 36
// move the bytes to the 'right'
for(from = in->size, to = size; from > 0;)
in->buffer[--to] = in->buffer[--from]; 40
41 // 'to' will always be greater than 0 because we checked for equal above. 42 for(; to > 0;)
43 in->buffer[--to] = 0; 44
in->size = (UINT16)size;
return TRUE; 47 }
This function to subtract one unsigned value from another c = a - b. c may be the same as a or b.
Return Value | Meaning |
1 | if (a > b) so no borrow |
0 | if (a = b) so no borrow and b == a |
-1 | if (a < b) so there was a borrow |
48 | LIB_EXPORT int | ||||||
49 | _math sub( | ||||||
50 | const UINT32 | aSize, | // | IN: | size | of | a |
51 | const BYTE | *a, | // | IN: | a | ||
52 | const UINT32 | bSize, | // | IN: | size | of | b |
53 | const BYTE | *b, | // | IN: | b | ||
54 | UINT16 | *cSize, | // | OUT: set | to MAX(aSize, bSize) | ||
55 | BYTE | *c | // | OUT: the | difference | ||
56 | ) |
57 | { | |
58 | int borrow = 0; | |
59 | int notZero = 0; | |
60 | int i; | |
61 | int i2; | |
62 | ||
63 | // set c to the longer of a or b | |
64 | *cSize = (UINT16)((aSize > bSize) ? aSize : bSize); | |
65 | // pick the shorter of a and b | |
66 | i = (aSize > bSize) ? bSize : aSize; | |
67 | i2 = *cSize - i; | |
68 | a = &a[aSize - 1]; | |
69 | b = &b[bSize - 1]; | |
70 | c = &c[*cSize - 1]; | |
71 | for(; i > 0; i--) | |
72 | { | |
73 | borrow = *a-- - *b-- + borrow; | |
74 | *c-- = (BYTE)borrow; | |
75 | notZero = notZero || borrow; | |
76 | borrow >>= 8; | |
77 | } | |
78 | if(aSize > bSize) | |
79 | { | |
80 | for(;i2 > 0; i2--) | |
81 | { | |
82 | borrow = *a-- + borrow; | |
83 | *c-- = (BYTE)borrow; | |
84 | notZero = notZero || borrow; | |
85 | borrow >>= 8; | |
86 | } | |
87 | } | |
88 | else if(aSize < bSize) | |
89 | { | |
90 | for(;i2 > 0; i2--) | |
91 | { | |
92 | borrow = 0 - *b-- + borrow; | |
93 | *c-- = (BYTE)borrow; | |
94 | notZero = notZero || borrow; | |
95 | borrow >>= 8; | |
96 | } | |
97 | } | |
98 | // if there is a borrow, then b > a | |
99 | if(borrow) | |
100 | return -1; | |
101 | // either a > b or they are the same | |
102 | return notZero; | |
103 | } |
This function increments a large, big-endian number value by one.
Return Value | Meaning |
0 | result is zero |
!0 | result is not zero |
104 | LIB_EXPORT int | ||
105 | _math Inc( | ||
106 | UINT32 | aSize, | // IN: size of a |
107 | BYTE | *a | // IN: a |
108 | ) | ||
109 | { |
110 | ||
111 | for(a = &a[aSize-1];aSize > 0; aSize--) | |
112 | { | |
113 | if((*a-- += 1) != 0) | |
114 | return 1; | |
115 | } | |
116 | return 0; | |
117 | } | |
This function decrements a large, ENDIAN value by one. | ||
118 | LIB_EXPORT void | |
119 | _math Dec( | |
120 | UINT32 aSize, // IN: size | of a |
121 | BYTE *a // IN: a | |
122 | ) | |
123 | { | |
124 | for(a = &a[aSize-1]; aSize > 0; aSize--) | |
125 | { | |
126 | if((*a-- -= 1) != 0xff) | |
127 | return; | |
128 | } | |
129 | return; | |
130 | } | |
This function is used to multiply two large integers: p = a* b. If the size of p is not specified (pSize == NULL), the size of the results p is assumed to be aSize + bSize and the results are de-normalized so that the resulting size is exactly aSize + bSize. If pSize is provided, then the actual size of the result is returned. The initial value for pSize must be at least aSize + pSize.
Return Value | Meaning |
< 0 | indicates an error |
>= 0 | the size of the product |
LIB_EXPORT int
_math Mul(
const UINT32 aSize, // IN: size of a
const BYTE *a, // IN: a
const UINT32 bSize, // IN: size of b
const BYTE *b, // IN: b
UINT32 *pSize, // IN/OUT: size of the product
BYTE *p // OUT: product. length of product = aSize +
// bSize
140 )
141 {
BIGNUM *bnA;
BIGNUM *bnB;
BIGNUM *bnP;
BN_CTX *context;
int retVal = 0; 147
// First check that pSize is large enough if present
if((pSize != NULL) && (*pSize < (aSize + bSize)))
return CRYPT_PARAMETER;
pAssert(pSize == NULL || *pSize <= MAX_2B_BYTES); 152 //
153 | // Allocate space for BIGNUM context | |
154 | // | |
155 | context = BN_CTX_new(); | |
156 | if(context == NULL) | |
157 | FAIL(FATAL_ERROR_ALLOCATION); | |
158 | bnA = BN_CTX_get(context); | |
159 | bnB = BN_CTX_get(context); | |
160 | bnP = BN_CTX_get(context); | |
161 | if (bnP == NULL) | |
162 | FAIL(FATAL_ERROR_ALLOCATION); | |
163 | ||
164 | // Convert the inputs to BIGNUMs | |
165 | // | |
166 | if (BN_bin2bn(a, aSize, bnA) == NULL || BN_bin2bn(b, bSize, bnB) == NULL) | |
167 | FAIL(FATAL_ERROR_INTERNAL); | |
168 | ||
169 | // Perform the multiplication | |
170 | // | |
171 | if (BN_mul(bnP, bnA, bnB, context) != 1) | |
172 | FAIL(FATAL_ERROR_INTERNAL); | |
173 | ||
174 | // If the size of the results is allowed to float, then set the return | |
175 | // size. Otherwise, it might be necessary to de-normalize the results | |
176 | retVal = BN_num_bytes(bnP); | |
177 | if(pSize == NULL) | |
178 | { | |
179 | BN_bn2bin(bnP, &p[aSize + bSize - retVal]); | |
180 | memset(p, 0, aSize + bSize - retVal); | |
181 | retVal = aSize + bSize; | |
182 | } | |
183 | else | |
184 | { | |
185 | BN_bn2bin(bnP, p); | |
186 | *pSize = retVal; | |
187 | } | |
188 | ||
189 | BN_CTX_end(context); | |
190 | BN_CTX_free(context); | |
191 | return retVal; | |
192 | } |
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.
Return Value | Meaning |
CRYPT_SUCCESS | operation complete |
CRYPT_UNDERFLOW | q or r is too small to receive the result |
193 | LIB_EXPORT CRYPT_RESULT | ||
194 | _math Div( | ||
195 | const TPM2B *n, | // | IN: numerator |
196 | const TPM2B *d, | // | IN: denominator |
197 | TPM2B *q, | // | OUT: quotient |
198 | TPM2B *r | // | OUT: remainder |
199 | ) | ||
200 | { | ||
201 | BIGNUM *bnN; | ||
202 | BIGNUM *bnD; | ||
203 | BIGNUM *bnQ; | ||
204 | BIGNUM *bnR; |
BN_CTX *context;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 207
// Get structures for the big number representations
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnN = BN_CTX_get(context);
bnD = BN_CTX_get(context);
bnQ = BN_CTX_get(context);
bnR = BN_CTX_get(context); 217
// Errors in BN_CTX_get() are sticky so only need to check the last allocation
if ( bnR == NULL
|| BN_bin2bn(n->buffer, n->size, bnN) == NULL
|| BN_bin2bn(d->buffer, d->size, bnD) == NULL)
FAIL(FATAL_ERROR_INTERNAL); 223
// Check for divide by zero.
if(BN_num_bits(bnD) == 0)
FAIL(FATAL_ERROR_DIVIDE_ZERO); 227
// Perform the division
if (BN_div(bnQ, bnR, bnN, bnD, context) != 1)
FAIL(FATAL_ERROR_INTERNAL); 231
// Convert the BIGNUM result back to our format
if(q != NULL) // If the quotient is being returned
234 {
235 if(!BnTo2B(q, bnQ, q->size))
236 {
retVal = CRYPT_UNDERFLOW;
goto Done;
239 }
240 }
241 if(r != NULL) // If the remainder is being returned
242 {
if(!BnTo2B(r, bnR, r->size))
retVal = CRYPT_UNDERFLOW;
245 }
246
Done:
BN_CTX_end(context);
BN_CTX_free(context); 250
251 return retVal;
252 }
This function compare two unsigned values.
Return Value | Meaning |
1 | if (a > b) |
0 | if (a = b) |
-1 | if (a < b) |
253 | LIB_EXPORT int | ||||
254 | _math uComp( | ||||
255 | const UINT32 | aSize, | // | IN: | size of a |
256 | const BYTE | *a, | // | IN: | a |
const UINT32 bSize, // IN: size of b
const BYTE *b // IN: b
259 )
260 {
int borrow = 0;
int notZero = 0;
int i;
// If a has more digits than b, then a is greater than b if
// any of the more significant bytes is non zero
if((i = (int)aSize - (int)bSize) > 0) 267 for(; i > 0; i--)
if(*a++) // means a > b
return 1;
// If b has more digits than a, then b is greater if any of the
// more significant bytes is non zero
if(i < 0) // Means that b is longer than a 273 for(; i < 0; i++)
if(*b++) // means that b > a
return -1;
// Either the vales are the same size or the upper bytes of a or b are
// all zero, so compare the rest
i = (aSize > bSize) ? bSize : aSize; 279 a = &a[i-1];
280 b = &b[i-1];
281 for(; i > 0; i--)
282 {
borrow = *a-- - *b-- + borrow;
notZero = notZero || borrow;
borrow >>= 8;
286 }
// if there is a borrow, then b > a
if(borrow)
return -1;
// either a > b or they are the same
return notZero;
292 }
Compare two signed integers:
Return Value | Meaning |
1 | if a > b |
0 | if a = b |
-1 | if a < b |
293 | LIB_EXPORT int | |
294 | _math Comp( | |
295 | const UINT32 aSize, | // IN: size of a |
296 | const BYTE *a, | // IN: a buffer |
297 | const UINT32 bSize, | // IN: size of b |
298 | const BYTE *b | // IN: b buffer |
299 | ) | |
300 | { | |
301 | int signA, signB; | // sign of a and b |
302 | ||
303 | // For positive or 0, sign_a | is 1 |
304 | // for negative, sign_a is 0 | |
305 | signA = ((a[0] & 0x80) == 0) | ? 1 : 0; |
306 | ||
307 | // For positive or 0, sign_b | is 1 |
308 | // for negative, sign_b is 0 |
309 | signB = ((b[0] & 0x80) == 0) ? 1 : 0; | |
310 | ||
311 | if(signA != signB) | |
312 | { | |
313 | return signA - signB; | |
314 | } | |
315 | ||
316 | if(signA == 1) | |
317 | // do unsigned compare function | |
318 | return _math uComp(aSize, a, bSize, b); | |
319 | else | |
320 | // do unsigned compare the other way | |
321 | return 0 - _math uComp(aSize, a, bSize, b); | |
322 | } |
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.
Return Value | Meaning |
CRYPT_SUCCESS | exponentiation succeeded |
CRYPT_PARAMETER | number to exponentiate is larger than the modulus |
CRYPT_UNDERFLOW | result will not fit into the provided buffer |
LIB_EXPORT CRYPT_RESULT
_math ModExp(
UINT32 cSize, // IN: size of the result
BYTE *c, // OUT: results buffer
const UINT32 mSize, // IN: size of number to be exponentiated
const BYTE *m, // IN: number to be exponentiated
const UINT32 eSize, // IN: size of power
const BYTE *e, // IN: power
const UINT32 nSize, // IN: modulus size
const BYTE *n // IN: modulu
333 )
334 {
CRYPT_RESULT retVal = CRYPT_SUCCESS;
BN_CTX *context;
BIGNUM *bnC;
BIGNUM *bnM;
BIGNUM *bnE;
BIGNUM *bnN;
INT32 i; 342
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnC = BN_CTX_get(context);
bnM = BN_CTX_get(context);
bnE = BN_CTX_get(context);
bnN = BN_CTX_get(context); 351
// Errors for BN_CTX_get are sticky so only need to check last allocation
if(bnN == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 355
//convert arguments
if ( BN_bin2bn(m, mSize, bnM) == NULL
|| BN_bin2bn(e, eSize, bnE) == NULL
|| BN_bin2bn(n, nSize, bnN) == NULL)
FAIL(FATAL_ERROR_INTERNAL); 361
// Don't do exponentiation if the number being exponentiated is
// larger than the modulus.
if(BN_ucmp(bnM, bnN) >= 0)
365 {
retVal = CRYPT_PARAMETER;
goto Cleanup;
368 }
// Perform the exponentiation
if(!(BN_mod_exp(bnC, bnM, bnE, bnN, context)))
FAIL(FATAL_ERROR_INTERNAL); 372
// Convert the results
// Make sure that the results will fit in the provided buffer.
if((unsigned)BN_num_bytes(bnC) > cSize)
376 {
retVal = CRYPT_UNDERFLOW;
goto Cleanup;
379 }
i = cSize - BN_num_bytes(bnC);
BN_bn2bin(bnC, &c[i]);
memset(c, 0, i); 383
Cleanup:
// Free up allocated BN values
BN_CTX_end(context);
BN_CTX_free(context);
return retVal;
389 }
Check if an 32-bit integer is a prime.
Return Value | Meaning |
TRUE | if the integer is probably a prime |
FALSE | if the integer is definitely not a prime |
390 | LIB_EXPORT BOOL | |
391 | _math IsPrime( | |
392 | const UINT32 prime | |
393 | ) | |
394 | { | |
395 | int isPrime; | |
396 | BIGNUM *p; | |
397 | ||
398 | // Assume the size variables are not overflow, which should not | happen in |
399 | // the contexts that this function will be called. | |
400 | if((p = BN_new()) == NULL) | |
401 | FAIL(FATAL_ERROR_ALLOCATION); | |
402 | if(!BN_set_word(p, prime)) | |
403 | FAIL(FATAL_ERROR_INTERNAL); | |
404 | ||
405 | // | |
406 | // BN_is_prime returning -1 means that it ran into an error. |
407 | // It should only return 0 or 1 | |
408 | // | |
409 | if((isPrime = BN_is_prime_ex(p, BN_prime_checks, NULL, NULL)) < 0) | |
410 | FAIL(FATAL_ERROR_INTERNAL); | |
411 | ||
412 | if(p != NULL) | |
413 | BN_clear_free(p); | |
414 | return (isPrime == 1); | |
415 | } |
This file contains the interface to the initialization, startup and shutdown functions of the crypto library.
#include "OsslCryptoEngine.h"
static void Trap(const char *function, int line, int code);
FAIL_FUNCTION TpmFailFunction = (FAIL_FUNCTION)&Trap;
This is a shim function that is called when a failure occurs. It simply relays the call to the callback pointed to by TpmFailFunction(). It is only defined for the sake of NO_RETURN specifier that cannot be added to a function pointer with some compilers.
void
TpmFail(
const char *function,
int line,
int code)
9 {
10 TpmFailFunction(function, line, code); 11 }
This function is called if the caller to _cpri InitCryptoUnits() doesn't provide a call back address.
static void
Trap(
const char *function,
int line,
int code
17 )
18 {
UNREFERENCED(function);
UNREFERENCED(line);
UNREFERENCED(code);
abort(); 23 }
This function calls the initialization functions of the other crypto modules that are part of the crypto engine for this implementation. This function should be called as a result of _TPM_Init(). The parameter to this function is a call back function it TPM.lib that is called when the crypto engine has a failure.
LIB_EXPORT CRYPT_RESULT
_cpri InitCryptoUnits(
FAIL_FUNCTION failFunction 27 )
28 {
29 TpmFailFunction = failFunction; 30
_cpri RngStartup();
_cpri HashStartup();
_cpri SymStartup(); 34
#ifdef TPM_ALG_RSA
_cpri RsaStartup();
#endif 38
#ifdef TPM_ALG_ECC
_cpri EccStartup();
#endif 42
43 return CRYPT_SUCCESS; 44 }
This function calls the shutdown functions of the other crypto modules that are part of the crypto engine for this implementation.
LIB_EXPORT void
_cpri StopCryptoUnits(
void
48 )
49 {
50 return; 51 }
This function calls the startup functions of the other crypto modules that are part of the crypto engine for this implementation. This function should be called during processing of TPM2_Startup().
LIB_EXPORT BOOL
_cpri Startup(
void
55 )
56 {
57
return( _cpri HashStartup()
&& _cpri RngStartup()
#ifdef TPM_ALG_RSA
&& _cpri RsaStartup()
#endif // TPM_ALG_RSA
#ifdef TPM_ALG_ECC
&& _cpri EccStartup()
#endif // TPM_ALG_ECC
&& _cpri SymStartup()); 67 }
//#define TPM_RNG_FOR_DEBUG
This file contains the interface to the OpenSSL() random number functions.
#include "OsslCryptoEngine.h"
int s_entropyFailure;
This function is called to initialize the random number generator. It collects entropy from the platform to seed the OpenSSL() random number generator.
LIB_EXPORT BOOL
_cpri RngStartup(void) 6 {
UINT32 entropySize;
BYTE entropy[MAX_RNG_ENTROPY_SIZE];
INT32 returnedSize = 0; 10
// Initialize the entropy source
s_entropyFailure = FALSE;
_plat GetEntropy(NULL, 0); 14
// Collect entropy until we have enough
for(entropySize = 0;
entropySize < MAX_RNG_ENTROPY_SIZE && returnedSize >= 0;
entropySize += returnedSize) 19 {
returnedSize = _plat GetEntropy(&entropy[entropySize],
MAX_RNG_ENTROPY_SIZE - entropySize);
22 | } | |
23 | // Got some entropy on the last call and did not get an error | |
24 | if(returnedSize > 0) | |
25 | { | |
26 | // Seed OpenSSL with entropy | |
27 | RAND_seed(entropy, entropySize); | |
28 | } | |
29 | else | |
30 | { | |
31 | s_entropyFailure = TRUE; | |
32 | } | |
33 | return s_entropyFailure == FALSE; | |
34 | } |
This function is used to set the state of the RNG (direction == PUT_STATE) or to recover the state of the RNG (direction == GET_STATE).
NOTE: This not currently supported on OpenSSL() version.
LIB_EXPORT CRYPT_RESULT
_cpri DrbgGetPutState(
GET_PUT direction,
int bufferSize,
BYTE *buffer
40 )
41 {
UNREFERENCED_PARAMETER(direction);
UNREFERENCED_PARAMETER(bufferSize);
UNREFERENCED_PARAMETER(buffer); 45
46 return CRYPT_SUCCESS; // Function is not implemented 47 }
This function is called to add external entropy to the OpenSSL() random number generator.
LIB_EXPORT CRYPT_RESULT
_cpri StirRandom(
INT32 entropySize,
BYTE *entropy
52 )
53 {
54 if (entropySize >= 0)
55 {
56 RAND_add((const void *)entropy, (int) entropySize, 0.0); 57
58 }
59 return CRYPT_SUCCESS; 60 }
This function is called to get a string of random bytes from the OpenSSL() random number generator. The return value is the number of bytes placed in the buffer. If the number of bytes returned is not equal to the number of bytes requested (randomSize) it is indicative of a failure of the OpenSSL() random number generator and is probably fatal.
LIB_EXPORT UINT16
_cpri GenerateRandom(
INT32 randomSize,
BYTE *buffer
65 )
66 {
67 //
// We don't do negative sizes or ones that are too large
if (randomSize < 0 || randomSize > UINT16_MAX)
return 0;
// RAND_bytes uses 1 for success and we use 0
if(RAND_bytes(buffer, randomSize) == 1)
return (UINT16)randomSize;
else
return 0;
76 }
B.7.3.4.1. _cpri__GenerateSeededRandom()
This funciton is used to generate a pseudo-random number from some seed values This funciton returns the same result each time it is called with the same parameters
LIB_EXPORT UINT16
_cpri GenerateSeededRandom(
INT32 randomSize, // IN: the size of the request
BYTE *random, // OUT: receives the data
TPM_ALG_ID hashAlg, // IN: used by KDF version but not here
TPM2B *seed, // IN: the seed value
const char *label, // IN: a label string (optional)
TPM2B *partyU, // IN: other data (oprtional)
TPM2B *partyV // IN: still more (optional) 86 )
87 {
88
return (_cpri KDFa(hashAlg, seed, label, partyU, partyV,
randomSize * 8, random, NULL, FALSE)); 91 }
92 #endif //%
This file contains implementation of cryptographic functions for hashing.
#include "OsslCryptoEngine.h"
#include "CpriHashData.c"
#define OSSL_HASH_STATE_DATA_SIZE (MAX_HASH_STATE_SIZE - 8)
typedef struct {
union {
EVP_MD_CTX context;
BYTE data[OSSL_HASH_STATE_DATA_SIZE]; 8 } u;
9 INT16 copySize;
} OSSL_HASH_STATE;
Temporary aliasing of SM3 to SHA256 until SM3 is available
#define EVP_sm3_256 EVP_sha256
This function returns the address of the hash server function
static EVP_MD *
GetHashServer(
TPM_ALG_ID hashAlg 15 )
16 {
17 switch (hashAlg)
18 {
#ifdef TPM_ALG_SHA1
case TPM_ALG_SHA1:
return (EVP_MD *)EVP_sha1();
break;
#endif
#ifdef TPM_ALG_SHA256
case TPM_ALG_SHA256:
return (EVP_MD *)EVP_sha256();
break;
#endif
#ifdef TPM_ALG_SHA384
case TPM_ALG_SHA384:
return (EVP_MD *)EVP_sha384();
break;
#endif
#ifdef TPM_ALG_SHA512
case TPM_ALG_SHA512:
return (EVP_MD *)EVP_sha512();
break;
#endif
#ifdef TPM_ALG_SM3_256
case TPM_ALG_SM3_256:
return (EVP_MD *)EVP_sm3_256();
break;
#endif
case TPM_ALG_NULL:
return NULL;
default:
FAIL(FATAL_ERROR_INTERNAL); 48 }
49 }
This function copies an OpenSSL() hash context into a caller provided buffer.
Return Value | Meaning |
> 0 | the number of bytes of buf used. |
static UINT16
MarshalHashState(
EVP_MD_CTX *ctxt, // IN: Context to marshal
BYTE *buf // OUT: The buffer that will receive the
// context. This buffer is at least
// MAX_HASH_STATE_SIZE byte
56 )
57 {
// make sure everything will fit
pAssert(ctxt->digest->ctx_size <= OSSL_HASH_STATE_DATA_SIZE); 60
// Copy the context data
memcpy(buf, (void*) ctxt->md_data, ctxt->digest->ctx_size); 63
64 return (UINT16)ctxt->digest->ctx_size; 65 }
This function will unmarshal a caller provided buffer into an OpenSSL() hash context. The function returns the number of bytes copied (which may be zero).
static UINT16
GetHashState(
EVP_MD_CTX *ctxt, // OUT: The context structure to receive the
// result of unmarshaling.
TPM_ALG_ID algType, // IN: The hash algorithm selector
BYTE *buf // IN: Buffer containing marshaled hash data 72 )
73 {
74 EVP_MD *evpmdAlgorithm = NULL; 75
76 pAssert(ctxt != NULL); 77
78 EVP_MD_CTX_init(ctxt); 79
evpmdAlgorithm = GetHashServer(algType);
if(evpmdAlgorithm == NULL)
return 0;
83
// This also allocates the ctxt->md_data
if((EVP_DigestInit_ex(ctxt, evpmdAlgorithm, NULL)) != 1)
FAIL(FATAL_ERROR_INTERNAL); 87
pAssert(ctxt->digest->ctx_size < sizeof(ALIGNED_HASH_STATE));
memcpy(ctxt->md_data, buf, ctxt->digest->ctx_size);
return (UINT16)ctxt->digest->ctx_size; 91 }
This function returns a pointer to the hash info for the algorithm. If the algorithm is not supported, function returns a pointer to the data block associated with TPM_ALG_NULL.
static const HASH_INFO *
GetHashInfoPointer(
TPM_ALG_ID hashAlg
95 )
96 {
97 UINT32 i, tableSize; 98
// Get the table size of g_hashData
tableSize = sizeof(g_hashData) / sizeof(g_hashData[0]); 101
102 for(i = 0; i < tableSize - 1; i++)
103 {
if(g_hashData[i].alg == hashAlg)
return &g_hashData[i];
106 }
107 return &g_hashData[tableSize-1];
108 }
Function that is called to initialize the hash service. In this implementation, this function does nothing but it is called by the CryptUtilStartup() function and must be present.
LIB_EXPORT BOOL
_cpri HashStartup(
void
112 )
113 {
// On startup, make sure that the structure sizes are compatible. It would
// be nice if this could be done at compile time but I couldn't figure it out.
CPRI_HASH_STATE *cpriState = NULL;
// NUMBYTES evpCtxSize = sizeof(EVP_MD_CTX);
NUMBYTES cpriStateSize = sizeof(cpriState->state);
// OSSL_HASH_STATE *osslState;
NUMBYTES osslStateSize = sizeof(OSSL_HASH_STATE);
// int dataSize = sizeof(osslState->u.data);
pAssert(cpriStateSize >= osslStateSize); 123
124 return TRUE;
125 }
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 and index of 2 will return the last. All other index values will return TPM_ALG_NULL.
Return Value | Meaning |
TPM_ALG_xxx() | a hash algorithm |
TPM_ALG_NULL | this can be used as a stop value |
126 | LIB_EXPORT TPM_ALG_ID | ||
127 | _cpri GetHashAlgByIndex( | ||
128 | UINT32 index | // IN: the index | |
129 | ) | ||
130 | { | ||
131 | if(index >= HASH_COUNT) | ||
132 | return TPM_ALG_NULL; | ||
133 | return g_hashData[index].alg; | ||
134 | } |
Returns the size of the block used for the hash
Return Value | Meaning |
< 0 | the algorithm is not a supported hash |
>= | the digest size (0 for TPM_ALG_NULL) |
135 | LIB_EXPORT UINT16 | |
136 | _cpri GetHashBlockSize( | |
137 | TPM_ALG_ID hashAlg // IN: hash algorithm | to look up |
138 | ) | |
139 | { | |
140 | return GetHashInfoPointer(hashAlg)->blockSize; | |
141 | } |
This function returns a pointer to the DER string for the algorithm and indicates its size.
142 | LIB_EXPORT UINT16 | |
143 | _cpri GetHashDER( | |
144 | TPM_ALG_ID hashAlg, | // IN: the algorithm to look up |
145 | const BYTE **p | |
146 | ) | |
147 | { | |
148 | const HASH_INFO *q; | |
149 | q = GetHashInfoPointer(hashAlg); | |
150 | *p = &q->der[0]; | |
151 | return q->derSize; | |
152 | } |
Gets the digest size of the algorithm. The algorithm is required to be supported.
Return Value | Meaning |
=0 | the digest size for TPM_ALG_NULL |
>0 | the digest size of a hash algorithm |
LIB_EXPORT UINT16
_cpri GetDigestSize(
TPM_ALG_ID hashAlg // IN: hash algorithm to look up
156 )
157 {
158 return GetHashInfoPointer(hashAlg)->digestSize;
159 }
This function returns the algorithm associated with a hash context
LIB_EXPORT TPM_ALG_ID
_cpri GetContextAlg(
CPRI_HASH_STATE *hashState // IN: the hash context
163 )
164 {
165 return hashState->hashAlg;
166 }
This function is used to clone a CPRI_HASH_STATE. The return value is the size of the state.
LIB_EXPORT UINT16
_cpri CopyHashState (
CPRI_HASH_STATE *out, // OUT: destination of the state
CPRI_HASH_STATE *in // IN: source of the state
171 )
172 {
OSSL_HASH_STATE *i = (OSSL_HASH_STATE *)&in->state;
OSSL_HASH_STATE *o = (OSSL_HASH_STATE *)&out->state;
pAssert(sizeof(i) <= sizeof(in->state)); 176
EVP_MD_CTX_init(&o->u.context);
EVP_MD_CTX_copy_ex(&o->u.context, &i->u.context);
o->copySize = i->copySize;
out->hashAlg = in->hashAlg;
return sizeof(CPRI_HASH_STATE);
182 }
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.
Return Value | Meaning |
0 | hash is TPM_ALG_NULL |
>0 | digest size |
183 | LIB_EXPORT UINT16 | ||||
184 | _cpri StartHash( | ||||
185 | TPM_ALG_ID | hashAlg, | // | IN: hash | algorithm |
186 | BOOL | sequence, | // | IN: TRUE | if the state should be saved |
187 | CPRI_HASH_STATE | *hashState | // | OUT: the | state of hash stack. |
188 | ) | ||||
189 | { | ||||
190 | EVP_MD_CTX | localState; |
OSSL_HASH_STATE *state = (OSSL_HASH_STATE *)&hashState->state;
BYTE *stateData = state->u.data;
EVP_MD_CTX *context;
EVP_MD *evpmdAlgorithm = NULL;
UINT16 retVal = 0; 196
if(sequence)
context = &localState;
else
context = &state->u.context; 201
202 hashState->hashAlg = hashAlg; 203
EVP_MD_CTX_init(context);
evpmdAlgorithm = GetHashServer(hashAlg);
if(evpmdAlgorithm == NULL)
goto Cleanup; 208
if(EVP_DigestInit_ex(context, evpmdAlgorithm, NULL) != 1)
FAIL(FATAL_ERROR_INTERNAL);
retVal = (CRYPT_RESULT)EVP_MD_CTX_size(context); 212
Cleanup:
if(retVal > 0)
215 {
216 if (sequence)
217 {
218 if((state->copySize = MarshalHashState(context, stateData)) == 0)
219 {
// If MarshalHashState returns a negative number, it is an error
// code and not a hash size so copy the error code to be the return
// from this function and set the actual stateSize to zero.
retVal = state->copySize;
state->copySize = 0;
225 }
// Do the cleanup
EVP_MD_CTX_cleanup(context);
228 }
else
state->copySize = -1;
231 }
else
state->copySize = 0;
return retVal;
235 }
Add data to a hash or HMAC stack.
LIB_EXPORT void
_cpri UpdateHash(
CPRI_HASH_STATE *hashState, // IN: the hash context information
UINT32 dataSize, // IN: the size of data to be added to the
// digest
BYTE *data // IN: data to be hashed
242 )
243 {
EVP_MD_CTX localContext;
OSSL_HASH_STATE *state = (OSSL_HASH_STATE *)&hashState->state;
BYTE *stateData = state->u.data;
EVP_MD_CTX *context;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 249
250 | // If there is no context, return | |
251 | if(state->copySize == 0) | |
252 | return; | |
253 | if(state->copySize > 0) | |
254 | { | |
255 | context = &localContext; | |
256 | if((retVal = GetHashState(context, hashState->hashAlg, stateData)) <= 0) | |
257 | return; | |
258 | } | |
259 | else | |
260 | context = &state->u.context; | |
261 | ||
262 | if(EVP_DigestUpdate(context, data, dataSize) != 1) | |
263 | FAIL(FATAL_ERROR_INTERNAL); | |
264 | else if( state->copySize > 0 | |
265 | && (retVal= MarshalHashState(context, stateData)) >= 0) | |
266 | { | |
267 | // retVal is the size of the marshaled data. Make sure that it is consistent | |
268 | // by ensuring that we didn't get more than allowed | |
269 | if(retVal < state->copySize) | |
270 | FAIL(FATAL_ERROR_INTERNAL); | |
271 | else | |
272 | EVP_MD_CTX_cleanup(context); | |
273 | } | |
274 | return; | |
275 | } |
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.
Return Value | Meaning |
0 | no data returned |
> 0 | the number of bytes in the digest |
LIB_EXPORT UINT16
_cpri CompleteHash(
CPRI_HASH_STATE *hashState, // IN: the state of hash stack
UINT32 dOutSize, // IN: size of digest buffer
BYTE *dOut // OUT: hash digest
281 )
282 {
EVP_MD_CTX localState;
OSSL_HASH_STATE *state = (OSSL_HASH_STATE *)&hashState->state;
BYTE *stateData = state->u.data;
EVP_MD_CTX *context;
UINT16 retVal;
int hLen;
BYTE temp[MAX_DIGEST_SIZE];
BYTE *rBuffer = dOut; 291
if(state->copySize == 0)
return 0;
if(state->copySize > 0)
295 {
context = &localState;
if((retVal = GetHashState(context, hashState->hashAlg, stateData)) <= 0)
goto Cleanup;
299 }
else
context = &state->u.context; 302
hLen = EVP_MD_CTX_size(context);
if((unsigned)hLen > dOutSize)
rBuffer = temp;
if(EVP_DigestFinal_ex(context, rBuffer, NULL) == 1)
307 {
308 if(rBuffer != dOut)
309 {
310 if(dOut != NULL)
311 {
312 memcpy(dOut, temp, dOutSize);
313 }
314 retVal = (UINT16)dOutSize;
315 }
316 else
317 {
318 retVal = (UINT16)hLen;
319 }
320 state->copySize = 0;
321 }
322 else
323 {
324 retVal = 0; // Indicate that no data is returned
325 }
Cleanup:
EVP_MD_CTX_cleanup(context);
return retVal;
329 }
_cpri__ImportExportHashState()
This function is used to import or export the hash state. This function would be called to export state when a sequence object was being prepared for export
LIB_EXPORT void
_cpri ImportExportHashState(
CPRI_HASH_STATE *osslFmt, // IN/OUT: the hash state formated for use
// by openSSL
EXPORT_HASH_STATE *externalFmt, // IN/OUT: the exported hash state
IMPORT_EXPORT direction //
336 )
337 {
UNREFERENCED_PARAMETER(direction);
UNREFERENCED_PARAMETER(externalFmt);
UNREFERENCED_PARAMETER(osslFmt);
return; 342
#if 0
if(direction == IMPORT_STATE)
345 {
// don't have the import export functions yet so just copy
_cpri CopyHashState(osslFmt, (CPRI_HASH_STATE *)externalFmt);
348 }
349 else
350 {
351 _cpri CopyHashState((CPRI_HASH_STATE *)externalFmt, osslFmt);
352 }
353 #endif
354 }
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.
Return Value | Meaning |
>= 0 | number of bytes in digest (may be zero) |
LIB_EXPORT UINT16
_cpri HashBlock(
TPM_ALG_ID hashAlg, // IN: The hash algorithm
UINT32 dataSize, // IN: size of buffer to hash
BYTE *data, // IN: the buffer to hash
UINT32 digestSize, // IN: size of the digest buffer
BYTE *digest // OUT: hash digest
362 )
363 {
EVP_MD_CTX hashContext;
EVP_MD *hashServer = NULL;
UINT16 retVal = 0;
BYTE b[MAX_DIGEST_SIZE]; // temp buffer in case digestSize not
// a full digest
unsigned int dSize = _cpri GetDigestSize(hashAlg); 370
// If there is no digest to compute return
if(dSize == 0)
return 0; 374
// After the call to EVP_MD_CTX_init(), will need to call EVP_MD_CTX_cleanup()
EVP_MD_CTX_init(&hashContext); // Initialize the local hash context
hashServer = GetHashServer(hashAlg); // Find the hash server 378
// It is an error if the digest size is non-zero but there is no server
if( (hashServer == NULL)
|| (EVP_DigestInit_ex(&hashContext, hashServer, NULL) != 1)
|| (EVP_DigestUpdate(&hashContext, data, dataSize) != 1))
FAIL(FATAL_ERROR_INTERNAL);
else
385 {
// If the size of the digest produced (dSize) is larger than the available
// buffer (digestSize), then put the digest in a temp buffer and only copy
// the most significant part into the available buffer.
if(dSize > digestSize)
390 {
if(EVP_DigestFinal_ex(&hashContext, b, &dSize) != 1)
FAIL(FATAL_ERROR_INTERNAL);
memcpy(digest, b, digestSize);
retVal = (UINT16)digestSize;
395 }
396 else
397 {
if((EVP_DigestFinal_ex(&hashContext, digest, &dSize)) != 1)
FAIL(FATAL_ERROR_INTERNAL);
retVal = (UINT16) dSize;
401 }
402 }
403 EVP_MD_CTX_cleanup(&hashContext);
404 return retVal;
405 }
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.
Return Value | Meaning |
>= 0 | number of bytes in digest produced by hashAlg (may be zero) |
LIB_EXPORT UINT16
_cpri StartHMAC(
TPM_ALG_ID hashAlg, // IN: the algorithm to use
BOOL sequence, // IN: indicates if the state should be
// saved
CPRI_HASH_STATE *state, // IN/OUT: the state buffer
UINT16 keySize, // IN: the size of the HMAC key
BYTE *key, // IN: the HMAC key
TPM2B *oPadKey // OUT: the key prepared for the oPad round
415 )
416 {
417 CPRI_HASH_STATE localState;
418 UINT16 blockSize = _cpri GetHashBlockSize(hashAlg);
419 UINT16 digestSize;
420 BYTE *pb; // temp pointer
421 UINT32 i; 422
423 // If the key size is larger than the block size, then the hash of the key
424 // is used as the key
425 if(keySize > blockSize)
426 {
// large key so digest
if((digestSize = _cpri StartHash(hashAlg, FALSE, &localState)) == 0)
return 0;
_cpri UpdateHash(&localState, keySize, key);
_cpri CompleteHash(&localState, digestSize, oPadKey->buffer);
oPadKey->size = digestSize;
433 }
434 else
435 {
436 // key size is ok
437 memcpy(oPadKey->buffer, key, keySize);
438 oPadKey->size = keySize;
439 }
440 // XOR the key with iPad (0x36)
441 pb = oPadKey->buffer;
442 for(i = oPadKey->size; i > 0; i--) 443 *pb++ ^= 0x36;
444
445 // if the keySize is smaller than a block, fill the rest with 0x36
446 for(i = blockSize - oPadKey->size; i > 0; i--) 447 *pb++ = 0x36;
448
449 // Increase the oPadSize to a full block
450 oPadKey->size = blockSize; 451
452 // Start a new hash with the HMAC key
453 // This will go in the caller's state structure and may be a sequence or not 454
455 if((digestSize = _cpri StartHash(hashAlg, sequence, state)) > 0)
456 {
457
458 _cpri UpdateHash(state, oPadKey->size, oPadKey->buffer); 459
460 // XOR the key block with 0x5c ^ 0x36
461 for(pb = oPadKey->buffer, i = blockSize; i > 0; i--) 462 *pb++ ^= (0x5c ^ 0x36);
463 | } | |
464 | ||
465 | return digestSize; | |
466 | } |
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.
Return Value | Meaning |
>= 0 | number of bytes in dOut (may be zero) |
LIB_EXPORT UINT16
_cpri CompleteHMAC(
CPRI_HASH_STATE *hashState, // IN: the state of hash stack
TPM2B *oPadKey, // IN: the HMAC key in oPad format
UINT32 dOutSize, // IN: size of digest buffer
BYTE *dOut // OUT: hash digest
473 )
474 {
475 BYTE digest[MAX_DIGEST_SIZE];
476 CPRI_HASH_STATE *state = (CPRI_HASH_STATE *)hashState;
477 CPRI_HASH_STATE localState;
478 UINT16 digestSize = _cpri GetDigestSize(state->hashAlg); 479
480 _cpri CompleteHash(hashState, digestSize, digest); 481
482 // Using the local hash state, do a hash with the oPad
483 if(_cpri StartHash(state->hashAlg, FALSE, &localState) != digestSize)
484 return 0; 485
486 _cpri UpdateHash(&localState, oPadKey->size, oPadKey->buffer);
487 _cpri UpdateHash(&localState, digestSize, digest);
488 return _cpri CompleteHash(&localState, dOutSize, dOut);
489 }
Mask and Key Generation Functions
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
Return Value | Meaning |
0 | hash algorithm not supported |
> 0 | should be the same as mSize |
LIB_EXPORT CRYPT_RESULT
_cpri MGF1(
UINT32 mSize, // IN: length of the mask to be produced
BYTE *mask, // OUT: buffer to receive the mask
TPM_ALG_ID hashAlg, // IN: hash to use
UINT32 sSize, // IN: size of the seed
BYTE *seed // IN: seed size
497 )
498 {
EVP_MD_CTX hashContext;
EVP_MD *hashServer = NULL;
CRYPT_RESULT retVal = 0;
BYTE b[MAX_DIGEST_SIZE]; // temp buffer in case mask is not an
// even multiple of a full digest
CRYPT_RESULT dSize = _cpri GetDigestSize(hashAlg);
unsigned int digestSize = (UINT32)dSize;
UINT32 remaining;
UINT32 counter;
BYTE swappedCounter[4]; 509
510 // Parameter check
511 if(mSize > (1024*16)) // Semi-arbitrary maximum
512 FAIL(FATAL_ERROR_INTERNAL); 513
514 // If there is no digest to compute return
515 if(dSize <= 0)
516 return 0; 517
518 EVP_MD_CTX_init(&hashContext); // Initialize the local hash context
519 hashServer = GetHashServer(hashAlg); // Find the hash server
520 if(hashServer == NULL)
521 // If there is no server, then there is no digest
522 return 0; 523
524 for(counter = 0, remaining = mSize; remaining > 0; counter++)
525 {
526 // Because the system may be either Endian...
527 UINT32_TO_BYTE_ARRAY(counter, swappedCounter); 528
529 // Start the hash and include the seed and counter
530 if( (EVP_DigestInit_ex(&hashContext, hashServer, NULL) != 1)
531 || (EVP_DigestUpdate(&hashContext, seed, sSize) != 1)
532 || (EVP_DigestUpdate(&hashContext, swappedCounter, 4) != 1)
533 )
534 FAIL(FATAL_ERROR_INTERNAL); 535
536 // Handling the completion depends on how much space remains in the mask
537 // buffer. If it can hold the entire digest, put it there. If not
538 // put the digest in a temp buffer and only copy the amount that
539 // will fit into the mask buffer.
540 if(remaining < (unsigned)dSize)
541 {
542 if(EVP_DigestFinal_ex(&hashContext, b, &digestSize) != 1)
543 FAIL(FATAL_ERROR_INTERNAL);
544 memcpy(mask, b, remaining);
545 break;
546 }
547 else
548 {
549 if(EVP_DigestFinal_ex(&hashContext, mask, &digestSize) != 1)
550 FAIL(FATAL_ERROR_INTERNAL);
551 remaining -= dSize;
552 mask = &mask[dSize];
553 }
554 retVal = (CRYPT_RESULT)mSize;
555 }
556
557 EVP_MD_CTX_cleanup(&hashContext);
558 return retVal;
559 }
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.
Return Value | Meaning |
0 | hash algorithm is not supported or is TPM_ALG_NULL |
> 0 | the number of bytes in the keyStream buffer |
LIB_EXPORT UINT16
_cpri KDFa(
TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC
TPM2B *key, // IN: HMAC key
const char *label, // IN: a 0-byte terminated label used in KDF
TPM2B *contextU, // IN: context U
TPM2B *contextV, // IN: context V
UINT32 sizeInBits, // IN: size of generated key in bit
BYTE *keyStream, // OUT: key buffer
UINT32 *counterInOut, // IN/OUT: caller may provide the iteration
// counter for incremental operations to
// avoid large intermediate buffers.
BOOL once // IN: TRUE if only one iteration is performed
// FALSE if iteration count determined by
// "sizeInBits"
575 )
576 {
UINT32 counter = 0; // counter value
INT32 lLen = 0; // length of the label
INT16 hLen; // length of the hash
INT16 bytes; // number of bytes to produce
BYTE *stream = keyStream;
BYTE marshaledUint32[4];
CPRI_HASH_STATE hashState;
TPM2B_MAX_HASH_BLOCK hmacKey; 585
586 pAssert(key != NULL && keyStream != NULL);
587 pAssert(once == FALSE || (sizeInBits & 7) == 0); 588
589 if(counterInOut != NULL)
590 counter = *counterInOut; 591
592 // Prepare label buffer. Calculate its size and keep the last 0 byte
593 if(label != NULL)
594 for(lLen = 0; label[lLen++] != 0; ); 595
596 // Get the hash size. If it is less than or 0, either the
597 // algorithm is not supported or the hash is TPM_ALG_NULL
598 // In either case the digest size is zero. This is the only return
599 // other than the one at the end. All other exits from this function 600 // are fatal errors. After we check that the algorithm is supported 601 // anything else that goes wrong is an implementation flaw.
602 if((hLen = (INT16) _cpri GetDigestSize(hashAlg)) == 0) 603 return 0;
604
605 // If the size of the request is larger than the numbers will handle, 606 // it is a fatal error.
607 pAssert(((sizeInBits + 7)/ 8) <= INT16_MAX); 608
609 bytes = once ? hLen : (INT16)((sizeInBits + 7) / 8); 610
611 // Generate required bytes
612 for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen) 613 {
614 if(bytes < hLen)
615 hLen = bytes; 616
counter++;
// Start HMAC
if(_cpri StartHMAC(hashAlg,
FALSE,
&hashState,
key->size,
&key->buffer[0],
&hmacKey.b) <= 0)
FAIL(FATAL_ERROR_INTERNAL);
626
627 // Adding counter
628 UINT32_TO_BYTE_ARRAY(counter, marshaledUint32);
629 _cpri UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); 630
631 // Adding label
632 if(label != NULL)
633 _cpri UpdateHash(&hashState, lLen, (BYTE *)label); 634
635 // Adding contextU
636 if(contextU != NULL)
637 _cpri UpdateHash(&hashState, contextU->size, contextU->buffer); 638
639 // Adding contextV
640 if(contextV != NULL)
641 _cpri UpdateHash(&hashState, contextV->size, contextV->buffer); 642
643 // Adding size in bits
644 UINT32_TO_BYTE_ARRAY(sizeInBits, marshaledUint32);
645 _cpri UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); 646
647 // Compute HMAC. At the start of each iteration, hLen is set
648 // to the smaller of hLen and bytes. This causes bytes to decrement 649 // exactly to zero to complete the loop
650 _cpri CompleteHMAC(&hashState, &hmacKey.b, hLen, stream);
651 | } | |
652 | ||
653 | // Mask off bits if the required bits is not a multiple of byte size | |
654 | if((sizeInBits % 8) != 0) | |
655 | keyStream[0] &= ((1 << (sizeInBits % 8)) - 1); | |
656 | if(counterInOut != NULL) | |
657 | *counterInOut = counter; | |
658 | return (CRYPT_RESULT)((sizeInBits + 7)/8); | |
659 | } |
KDFe() as defined in TPM specification part 1.
This function returns the number of bytes generated which may be zero.
The Z 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). Any error in the processing of this command is considered fatal.
Return Value | Meaning |
0 | hash algorithm is not supported or is TPM_ALG_NULL |
> 0 | the number of bytes in the keyStream buffer |
660 LIB_EXPORT UINT16
661 _cpri KDFe(
662 TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC 663 TPM2B *Z, // IN: Z
664 const char *label, // IN: a 0 terminated label using in KDF 665 TPM2B *partyUInfo, // IN: PartyUInfo
666 TPM2B *partyVInfo, // IN: PartyVInfo
667 UINT32 sizeInBits, // IN: size of generated key in bit 668 BYTE *keyStream // OUT: key buffer
669 )
670 {
671 UINT32 counter = 0; // counter value 672 UINT32 lSize = 0;
673 BYTE *stream = keyStream; 674 CPRI_HASH_STATE hashState;
675 INT16 hLen = (INT16) _cpri GetDigestSize(hashAlg); 676 INT16 bytes; // number of bytes to generate 677 BYTE marshaledUint32[4];
678
679 pAssert( keyStream != NULL 680 && Z != NULL
681 && ((sizeInBits + 7) / 8) < INT16_MAX);
682
683 if(hLen == 0)
684 return 0;
685
686 bytes = (INT16)((sizeInBits + 7) / 8);
687
688 // Prepare label buffer. Calculate its size and keep the last 0 byte 689 if(label != NULL)
690 for(lSize = 0; label[lSize++] != 0;);
691
692 // Generate required bytes
693 //The inner loop of that KDF uses:
694 // Hashi := H(counter | Z | OtherInfo) (5) 695 // Where:
696 // Hashi the hash generated on the i-th iteration of the loop. 697 // H() an approved hash function
698 // counter a 32-bit counter that is initialized to 1 and incremented 699 // on each iteration
700 // Z the X coordinate of the product of a public ECC key and a 701 // different private ECC key.
702 // OtherInfo a collection of qualifying data for the KDF defined below. 703 // In this specification, OtherInfo will be constructed by:
704 // OtherInfo := Use | PartyUInfo | PartyVInfo
705 for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen) 706 {
707 if(bytes < hLen)
708 hLen = bytes;
709 | ||
710 | counter++; | |
711 | // Start hash | |
712 | if(_cpri StartHash(hashAlg, FALSE, &hashState) == 0) | |
713 | return 0; | |
714 | ||
715 | // Add counter | |
716 | UINT32_TO_BYTE_ARRAY(counter, marshaledUint32); | |
717 | _cpri UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); | |
718 | ||
719 | // Add Z | |
720 | if(Z != NULL) | |
721 | _cpri UpdateHash(&hashState, Z->size, Z->buffer); | |
722 | ||
723 | // Add label | |
724 | if(label != NULL) | |
725 | _cpri UpdateHash(&hashState, lSize, (BYTE *)label); | |
726 | else | |
727 | ||
728 | // The SP800-108 specification requires a zero between the label | |
729 | // and the context. | |
730 | _cpri UpdateHash(&hashState, 1, (BYTE *)""); | |
731 | ||
732 | // Add PartyUInfo | |
733 | if(partyUInfo != NULL) | |
734 | _cpri UpdateHash(&hashState, partyUInfo->size, partyUInfo->buffer); | |
735 | ||
736 | // Add PartyVInfo | |
737 | if(partyVInfo != NULL) | |
738 | _cpri UpdateHash(&hashState, partyVInfo->size, partyVInfo->buffer); | |
739 | ||
740 | // Compute Hash. hLen was changed to be the smaller of bytes or hLen | |
741 | // at the start of each iteration. | |
742 | _cpri CompleteHash(&hashState, hLen, stream); | |
743 | } | |
744 | ||
745 | // Mask off bits if the required bits is not a multiple of byte size | |
746 | if((sizeInBits % 8) != 0) | |
747 | keyStream[0] &= ((1 << (sizeInBits % 8)) - 1); | |
748 | ||
749 | return (CRYPT_RESULT)((sizeInBits + 7) / 8); | |
750 | ||
751 | } |
This file should be included by the library hash module.
const HASH_INFO g_hashData[HASH_COUNT + 1] = {
#ifdef TPM_ALG_SHA1
{TPM_ALG_SHA1, SHA1_DIGEST_SIZE, SHA1_BLOCK_SIZE,
SHA1_DER_SIZE, SHA1_DER},
#endif
#ifdef TPM_ALG_SHA256
{TPM_ALG_SHA256, SHA256_DIGEST_SIZE, SHA256_BLOCK_SIZE,
SHA256_DER_SIZE, SHA256_DER},
#endif
#ifdef TPM_ALG_SHA384
{TPM_ALG_SHA384, SHA384_DIGEST_SIZE, SHA384_BLOCK_SIZE,
SHA384_DER_SIZE, SHA384_DER},
#endif
#ifdef TPM_ALG_SM3_256
{TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, SM3_256_BLOCK_SIZE, 16 SM3_256_DER_SIZE, SM3_256_DER},
#endif
#ifdef TPM_ALG_SHA512
{TPM_ALG_SHA512, SHA512_DIGEST_SIZE, SHA512_BLOCK_SIZE,
SHA512_DER_SIZE, SHA512_DER},
#endif
22 {TPM_ALG_NULL,0,0,0,{0}}
23 };
1 #include "OsslCryptoEngine.h"
This function is used to convert a BigNum() to a byte array of the specified size. If the number is too large to fit, then 0 is returned. Otherwise, the number is converted into the low-order bytes of the provided array and the upper bytes are set to zero.
Return Value | Meaning |
0 | failure (probably fatal) |
1 | conversion successful |
2 | BOOL | |||
3 | BnTo2B( | |||
4 | TPM2B | *outVal, | // | OUT: place for the result |
5 | BIGNUM | *inVal, | // | IN: number to convert |
6 UINT16 size // IN: size of the output. 7 )
8 {
9 BYTE *pb = outVal->buffer; 10
11 outVal->size = size; 12
size = size - (((UINT16) BN_num_bits(inVal) + 7) / 8);
if(size < 0)
return FALSE;
for(;size > 0; size--) 17 *pb++ = 0;
BN_bn2bin(inVal, pb);
return TRUE; 20 }
This function copies a TPM2B structure. The compiler can't generate a copy of a TPM2B generic structure because the actual size is not known. This function performs the copy on any TPM2B pair. The size of the destination should have been checked before this call to make sure that it will hold the TPM2B being copied.
This replicates the functionality in the MemoryLib.c.
void
Copy2B(
TPM2B *out, // OUT: The TPM2B to receive the copy
TPM2B *in // IN: the TPM2B to copy 25 )
26 {
BYTE *pIn = in->buffer;
BYTE *pOut = out->buffer;
int count;
out->size = in->size;
for(count = in->size; count > 0; count--)
32 *pOut++ = *pIn++;
33 return; 34 }
This function creates a BIGNUM from a TPM2B and fails if the conversion fails.
BIGNUM *
BnFrom2B(
BIGNUM *out, // OUT: The BIGNUM
const TPM2B *in // IN: the TPM2B to copy 39 )
40 {
if(BN_bin2bn(in->buffer, in->size, out) == NULL)
FAIL(FATAL_ERROR_INTERNAL);
return out; 44 }
This file contains the implementation of the symmetric block cipher modes allowed for a TPM. These function only use the single block encryption and decryption functions of OpesnSSL().
Currently, this module only supports AES encryption. The SM4 code actually calls an AES routine
1 #include "OsslCryptoEngine.h"
The following sets of defines are used to allow use of the SM4 algorithm identifier while waiting for the SM4 implementation code to appear.
2 | typedef AES_KEY SM4_KEY; | |
3 | #define SM4_set_encrypt_key | AES_set_encrypt_key |
4 | #define SM4_set_decrypt_key | AES_set_decrypt_key |
5 | #define SM4_decrypt | AES_decrypt |
6 | #define SM4_encrypt | AES_encrypt |
7 | LIB_EXPORT BOOL | |
8 | _cpri SymStartup( | |
9 | void | |
10 | ) | |
11 | { | |
12 | return TRUE; | |
13 | } |
B.11.3.2. _cpri__GetSymmetricBlockSize()
This function returns the block size of the algorithm.
Return Value | Meaning |
<= 0 | cipher not supported |
> 0 | the cipher block size in bytes |
LIB_EXPORT INT16
_cpri GetSymmetricBlockSize(
TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm
UINT16 keySizeInBits // IN: the key size 18 )
19 {
20 switch (symmetricAlg)
21 {
#ifdef TPM_ALG_AES
case TPM_ALG_AES:
#endif
#ifdef TPM_ALG_SM4 // Both AES and SM4 use the same block size
case TPM_ALG_SM4:
#endif
if(keySizeInBits != 0) // This is mostly to have a reference to
29 | // keySizeInBits for the compiler | |
30 | return 16; | |
31 | else | |
32 | return 0; | |
33 | break; | |
34 | ||
35 | default: | |
36 | return 0; | |
37 | } | |
38 | } |
This function performs AES encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to be a multiple of the block size.
Return Value | Meaning |
CRYPT_SUCCESS | if success |
CRYPT_PARAMETER | dInSize is not a multiple of the block size |
LIB_EXPORT CRYPT_RESULT
_cpri AESEncryptCBC(
BYTE *dOut, // OUT:
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption.
UINT32 dInSize, // IN: data size (is required to be a multiple
// of 16 bytes)
BYTE *dIn // IN: data buffer 49 )
50 {
AES_KEY AesKey;
BYTE *pIv;
INT32 dSize; // Need a signed version
int i; 55
56 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 57
if(dInSize == 0)
return CRYPT_SUCCESS; 60
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 63
// For CBC, the data size must be an even multiple of the
// cipher block size
66 if((dSize % 16) != 0)
67 return CRYPT_PARAMETER; 68
// Create AES encrypt key schedule
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 72
// XOR the data block into the IV, encrypt the IV into the IV
// and then copy the IV to the output
for(; dSize > 0; dSize -= 16) 76 {
77 | pIv = iv; | |
78 | for(i = 16; i > 0; i--) | |
79 | *pIv++ ^= *dIn++; | |
80 | AES_encrypt(iv, iv, &AesKey); | |
81 | pIv = iv; | |
82 | for(i = 16; i > 0; i--) | |
83 | *dOut++ = *pIv++; | |
84 | } | |
85 | return CRYPT_SUCCESS; | |
86 | } |
This function performs AES decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to be a multiple of the block size.
Return Value | Meaning |
CRYPT_SUCCESS | if success |
CRYPT_PARAMETER | dInSize is not a multiple of the block size |
LIB_EXPORT CRYPT_RESULT
_cpri AESDecryptCBC(
BYTE *dOut, // OUT: the decrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption. The size of this
// buffer is 16 byte
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer 97 )
98 {
AES_KEY AesKey;
BYTE *pIv;
int i;
BYTE tmp[16];
BYTE *pT = NULL;
INT32 dSize; 105
106 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 107
if(dInSize == 0)
return CRYPT_SUCCESS; 110
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 113
// For CBC, the data size must be an even multiple of the
// cipher block size
116 if((dSize % 16) != 0)
117 return CRYPT_PARAMETER; 118
// Create AES key schedule
if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 122
// Copy the input data to a temp buffer, decrypt the buffer into the output;
// XOR in the IV, and copy the temp buffer to the IV and repeat.
for(; dSize > 0; dSize -= 16)
126 {
127 | pT = tmp; | |
128 | for(i = 16; i> 0; i--) | |
129 | *pT++ = *dIn++; | |
130 | AES_decrypt(tmp, dOut, &AesKey); | |
131 | pIv = iv; | |
132 | pT = tmp; | |
133 | for(i = 16; i> 0; i--) | |
134 | { | |
135 | *dOut++ ^= *pIv; | |
136 | *pIv++ = *pT++; | |
137 | } | |
138 | } | |
139 | return CRYPT_SUCCESS; | |
140 | } |
This function performs AES encryption in CFB chain mode. The dOut buffer receives the values encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to contain the last encrypted block.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri AESEncryptCFB(
BYTE *dOut, // OUT: the encrypted
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption.
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
150 )
151 {
BYTE *pIv = NULL;
AES_KEY AesKey;
INT32 dSize; // Need a signed version of dInSize
int i; 156
157 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 158
if(dInSize == 0)
return CRYPT_SUCCESS; 161
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 164
// Create AES encryption key schedule
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 168
// Encrypt the IV into the IV, XOR in the data, and copy to output
for(; dSize > 0; dSize -= 16)
171 {
// Encrypt the current value of the IV
AES_encrypt(iv, iv, &AesKey);
pIv = iv;
175 for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
// XOR the data into the IV to create the cipher text
// and put into the output
178 *dOut++ = *pIv++ ^= *dIn++;
179 }
180 | // If the inner loop (i loop) was smaller than 16, then dSize would have been | |
181 | // smaller than 16 and it is now negative. If it is negative, then it indicates | |
182 | // how many bytes are needed to pad out the IV for the next round. | |
183 | for(; dSize < 0; dSize++) | |
184 | *pIv++ = 0; | |
185 | return CRYPT_SUCCESS; | |
186 | } |
This function performs AES decrypt in CFB chain mode. The dOut buffer receives the values decrypted from dIn.
The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to contain the last decoded block, padded with zeros
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri AESDecryptCFB(
BYTE *dOut, // OUT: the decrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption.
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
196 )
197 {
BYTE *pIv = NULL;
BYTE tmp[16];
int i;
BYTE *pT;
AES_KEY AesKey;
INT32 dSize; 204
205 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 206
if(dInSize == 0)
return CRYPT_SUCCESS; 209
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 212
// Create AES encryption key schedule
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 216
217 for(; dSize > 0; dSize -= 16)
218 {
// Encrypt the IV into the temp buffer
AES_encrypt(iv, tmp, &AesKey);
pT = tmp;
pIv = iv;
223 for(i = (dSize < 16) ? dSize : 16; i > 0; i--)
// Copy the current cipher text to IV, XOR
// with the temp buffer and put into the output
226 *dOut++ = *pT++ ^ (*pIv++ = *dIn++);
227 }
// If the inner loop (i loop) was smaller than 16, then dSize
// would have been smaller than 16 and it is now negative
// If it is negative, then it indicates how may fill bytes
231 | // are needed to pad out the IV for the next round. | |
232 | for(; dSize < 0; dSize++) | |
233 | *pIv++ = 0; | |
234 | ||
235 | return CRYPT_SUCCESS; | |
236 | } |
This function performs AES encryption/decryption in CTR chain mode. The dIn buffer is encrypted into dOut. The input iv buffer is assumed to have a size equal to the AES block size (16 bytes). The iv will be incremented by the number of blocks (full and partial) that were encrypted.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
237 | LIB_EXPORT CRYPT_RESULT | |
238 | _cpri AESEncryptCTR( | |
239 | BYTE *dOut, // OUT: the encrypted data | |
240 | UINT32 keySizeInBits, // IN: key size in bit | |
241 | BYTE *key, // IN: key buffer. The size of this buffer | in |
242 | // bytes is (keySizeInBits + 7) / 8 | |
243 | BYTE *iv, // IN/OUT: IV for decryption. | |
244 | UINT32 dInSize, // IN: data size | |
245 | BYTE *dIn // IN: data buffer | |
246 | ) | |
247 | { | |
248 | BYTE tmp[16]; | |
249 | BYTE *pT; | |
250 | AES_KEY AesKey; | |
251 | int i; | |
252 | INT32 dSize; | |
253 | ||
254 | pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); | |
255 | ||
256 | if(dInSize == 0) | |
257 | return CRYPT_SUCCESS; | |
258 | ||
259 | pAssert(dInSize <= INT32_MAX); | |
260 | dSize = (INT32)dInSize; | |
261 | ||
262 | // Create AES encryption schedule | |
263 | if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0) | |
264 | FAIL(FATAL_ERROR_INTERNAL); | |
265 | ||
266 | for(; dSize > 0; dSize -= 16) | |
267 | { | |
268 | // Encrypt the current value of the IV(counter) | |
269 | AES_encrypt(iv, (BYTE *)tmp, &AesKey); | |
270 | ||
271 | //increment the counter (counter is big-endian so start at end) | |
272 | for(i = 15; i >= 0; i--) | |
273 | if((iv[i] += 1) != 0) | |
274 | break; | |
275 | ||
276 | // XOR the encrypted counter value with input and put into output | |
277 | pT = tmp; | |
278 | for(i = (dSize < 16) ? dSize : 16; i > 0; i--) | |
279 | *dOut++ = *dIn++ ^ *pT++; | |
280 | } | |
281 | return CRYPT_SUCCESS; | |
282 | } |
Counter mode decryption uses the same algorithm as encryption. The _cpri__AESDecryptCTR() function is implemented as a macro call to _cpri AESEncryptCTR(). (skip)
//% #define _cpri AESDecryptCTR(dOut, keySize, key, iv, dInSize, dIn) \
//% _cpri AESEncryptCTR( \ 285 //% ((BYTE *)dOut), \
286 //% ((UINT32)keySize), \
287 //% ((BYTE *)key), \
288 //% ((BYTE *)iv), \
289 //% ((UINT32)dInSize), \
290 //% ((BYTE *)dIn) \
291 | //% ) | |
292 | //% | |
293 | // The //% is used by the prototype extraction program | to cause it to include the |
294 | // line in the prototype file after removing the //%. | Need an extra line with |
nothing on it so that a blank line will separate this macro from the next definition.
AES encryption in ECB mode. The data buffer is modified to contain the cipher text.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri AESEncryptECB(
BYTE *dOut, // OUT: encrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: clear text buffer
303 )
304 {
AES_KEY AesKey;
INT32 dSize; 307
308 pAssert(dOut != NULL && key != NULL && dIn != NULL); 309
if(dInSize == 0)
return CRYPT_SUCCESS; 312
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 315
// For ECB, the data size must be an even multiple of the
// cipher block size
318 if((dSize % 16) != 0)
return CRYPT_PARAMETER;
// Create AES encrypting key schedule
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 323
324 for(; dSize > 0; dSize -= 16)
325 {
326 AES_encrypt(dIn, dOut, &AesKey);
327 dIn = &dIn[16];
328 dOut = &dOut[16];
329 }
330 return CRYPT_SUCCESS;
331 }
This function performs AES decryption using ECB (not recommended). The cipher text dIn is decrypted into dOut.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
332 | LIB_EXPORT CRYPT_RESULT | |
333 | _cpri AESDecryptECB( | |
334 | BYTE *dOut, // OUT: the clear text data | |
335 | UINT32 keySizeInBits, // IN: key size in bit | |
336 | BYTE *key, // IN: key buffer. The size of | this buffer in |
337 | // bytes is (keySizeInBits | + 7) / 8 |
338 | UINT32 dInSize, // IN: data size | |
339 | BYTE *dIn // IN: cipher text buffer | |
340 | ) | |
341 | { | |
342 | AES_KEY AesKey; | |
343 | INT32 dSize; | |
344 | ||
345 | pAssert(dOut != NULL && key != NULL && dIn != NULL); | |
346 | ||
347 | if(dInSize == 0) | |
348 | return CRYPT_SUCCESS; | |
349 | ||
350 | pAssert(dInSize <= INT32_MAX); | |
351 | dSize = (INT32)dInSize; | |
352 | ||
353 | // For ECB, the data size must be an even multiple of the | |
354 | // cipher block size | |
355 | if((dSize % 16) != 0) | |
356 | return CRYPT_PARAMETER; | |
357 | ||
358 | // Create AES decryption key schedule | |
359 | if (AES_set_decrypt_key(key, keySizeInBits, &AesKey) != 0) | |
360 | FAIL(FATAL_ERROR_INTERNAL); | |
361 | ||
362 | for(; dSize > 0; dSize -= 16) | |
363 | { | |
364 | AES_decrypt(dIn, dOut, &AesKey); | |
365 | dIn = &dIn[16]; | |
366 | dOut = &dOut[16]; | |
367 | } | |
368 | return CRYPT_SUCCESS; | |
369 | } | |
This function performs AES encryption/decryption in OFB chain mode. The contain the encrypted/decrypted text. | dIn buffer is modified to |
The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri AESEncryptOFB(
BYTE *dOut, // OUT: the encrypted/decrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption. The size of this
// buffer is 16 byte
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
380 )
381 {
BYTE *pIv;
AES_KEY AesKey;
INT32 dSize;
int i; 386
387 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 388
if(dInSize == 0)
return CRYPT_SUCCESS; 391
pAssert(dInSize <= INT32_MAX);
dSize = (INT32)dInSize; 394
// Create AES key schedule
if (AES_set_encrypt_key(key, keySizeInBits, &AesKey) != 0)
FAIL(FATAL_ERROR_INTERNAL); 398
399 // This is written so that dIn and dOut may be the same 400
401 for(; dSize > 0; dSize -= 16)
402 {
403 // Encrypt the current value of the "IV"
404 AES_encrypt(iv, iv, &AesKey); 405
406 // XOR the encrypted IV into dIn to create the cipher text (dOut)
407 pIv = iv;
408 for(i = (dSize < 16) ? dSize : 16; i > 0; i--) 409 *dOut++ = (*pIv++ ^ *dIn++);
410 }
411 return CRYPT_SUCCESS;
412 }
B.11.4.10._cpri__AESDecryptOFB()
OFB encryption and decryption use the same algorithms for both. The _cpri__AESDecryptOFB() function is implemented as a macro call to _cpri AESEncrytOFB(). (skip)
413 | //%#define | _cpri AESDecryptOFB(dOut,keySizeInBits, key, iv, dInSize, dIn) \ | |
414 | //% | _cpri AESEncryptOFB ( \ | |
415 | //% | ((BYTE *)dOut), | \ |
416 | //% | ((UINT32)keySizeInBits), | \ |
417 | //% | ((BYTE *)key), | \ |
418 | //% | ((BYTE *)iv), | \ |
419 | //% | ((UINT32)dInSize), | \ |
420 | //% | ((BYTE *)dIn) | \ |
421 //% )
422 //%
423 #ifdef TPM_ALG_SM4 //%
This function performs SM4 encryption in CBC chain mode. The input dIn buffer is encrypted into dOut.
The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to be a multiple of the block size.
Return Value | Meaning |
CRYPT_SUCCESS | if success |
CRYPT_PARAMETER | dInSize is not a multiple of the block size |
424 | LIB_EXPORT CRYPT_RESULT | |
425 | _cpri SM4EncryptCBC( | |
426 | BYTE *dOut, // OUT: | |
427 | UINT32 keySizeInBits, // IN: key size in bit | |
428 | BYTE *key, // IN: key buffer. The size of this | buffer in |
429 | // bytes is (keySizeInBits + 7) | / 8 |
430 | BYTE *iv, // IN/OUT: IV for decryption. | |
431 | UINT32 dInSize, // IN: data size (is required to be | a multiple |
432 | // of 16 bytes) | |
433 | BYTE *dIn // IN: data buffer | |
434 | ) | |
435 | { | |
436 | SM4_KEY Sm4Key; | |
437 | BYTE *pIv; | |
438 | INT32 dSize; // Need a signed version | |
439 | int i; | |
440 | ||
441 | pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); | |
442 | ||
443 | if(dInSize == 0) | |
444 | return CRYPT_SUCCESS; | |
445 | ||
446 | pAssert(dInSize <= INT32_MAX); | |
447 | dSize = (INT32)dInSize; | |
448 | ||
449 | // For CBC, the data size must be an even multiple of the | |
450 | // cipher block size | |
451 | if((dSize % 16) != 0) | |
452 | return CRYPT_PARAMETER; | |
453 | ||
454 | // Create SM4 encrypt key schedule | |
455 | if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0) | |
456 | FAIL(FATAL_ERROR_INTERNAL); | |
457 | ||
458 | // XOR the data block into the IV, encrypt the IV into the IV | |
459 | // and then copy the IV to the output | |
460 | for(; dSize > 0; dSize -= 16) | |
461 | { | |
462 | pIv = iv; | |
463 | for(i = 16; i > 0; i--) | |
464 | *pIv++ ^= *dIn++; | |
465 | SM4_encrypt(iv, iv, &Sm4Key); | |
466 | pIv = iv; | |
467 | for(i = 16; i > 0; i--) | |
468 | *dOut++ = *pIv++; | |
469 | } | |
470 | return CRYPT_SUCCESS; |
471 }
This function performs SM4 decryption in CBC chain mode. The input dIn buffer is decrypted into dOut.
The input iv buffer is required to have a size equal to the block size (16 bytes). The dInSize is required to be a multiple of the block size.
Return Value | Meaning |
CRYPT_SUCCESS | if success |
CRYPT_PARAMETER | dInSize is not a multiple of the block size |
LIB_EXPORT CRYPT_RESULT
_cpri SM4DecryptCBC(
BYTE *dOut, // OUT: the decrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption. The size of this
// buffer is 16 byte
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
482 )
483 {
SM4_KEY Sm4Key;
BYTE *pIv;
int i;
BYTE tmp[16];
BYTE *pT = NULL;
INT32 dSize; 490
491 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 492
493 if(dInSize == 0)
494 return CRYPT_SUCCESS; 495
496 pAssert(dInSize <= INT32_MAX);
497 dSize = (INT32)dInSize; 498
499 // For CBC, the data size must be an even multiple of the
500 // cipher block size
501 if((dSize % 16) != 0)
502 return CRYPT_PARAMETER; 503
504 // Create SM4 key schedule
505 if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0)
506 FAIL(FATAL_ERROR_INTERNAL); 507
508 // Copy the input data to a temp buffer, decrypt the buffer into the output;
509 // XOR in the IV, and copy the temp buffer to the IV and repeat.
510 for(; dSize > 0; dSize -= 16)
511 {
512 pT = tmp;
513 for(i = 16; i> 0; i--) 514 *pT++ = *dIn++;
515 SM4_decrypt(tmp, dOut, &Sm4Key);
516 pIv = iv;
517 pT = tmp;
518 for(i = 16; i> 0; i--)
519 {
520 *dOut++ ^= *pIv;
521 | *pIv++ = *pT++; | |
522 | } | |
523 | } | |
524 | return CRYPT_SUCCESS; | |
525 | } |
This function performs SM4 encryption in CFB chain mode. The dOut buffer receives the values encrypted dIn. The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to contain the last encrypted block.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri SM4EncryptCFB(
BYTE *dOut, // OUT: the encrypted
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption.
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
535 )
536 {
537 BYTE *pIv;
538 SM4_KEY Sm4Key;
539 INT32 dSize; // Need a signed version of dInSize
540 int i; 541
542 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 543
544 if(dInSize == 0)
545 return CRYPT_SUCCESS; 546
547 pAssert(dInSize <= INT32_MAX);
548 dSize = (INT32)dInSize; 549
550 // Create SM4 encryption key schedule
551 if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
552 FAIL(FATAL_ERROR_INTERNAL); 553
554 // Encrypt the IV into the IV, XOR in the data, and copy to output
555 for(; dSize > 0; dSize -= 16)
556 {
557 // Encrypt the current value of the IV
558 SM4_encrypt(iv, iv, &Sm4Key);
559 pIv = iv;
560 for(i = (int)(dSize < 16) ? dSize : 16; i > 0; i--)
561 // XOR the data into the IV to create the cipher text
562 // and put into the output
563 *dOut++ = *pIv++ ^= *dIn++;
564 }
565 return CRYPT_SUCCESS;
566 }
This function performs SM4 decrypt in CFB chain mode. The dOut buffer receives the values decrypted from dIn.
The input iv is assumed to be the size of an encryption block (16 bytes). The iv buffer will be modified to contain the last decoded block, padded with zeros
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
LIB_EXPORT CRYPT_RESULT
_cpri SM4DecryptCFB(
BYTE *dOut, // OUT: the decrypted data
UINT32 keySizeInBits, // IN: key size in bit
BYTE *key, // IN: key buffer. The size of this buffer in
// bytes is (keySizeInBits + 7) / 8
BYTE *iv, // IN/OUT: IV for decryption.
UINT32 dInSize, // IN: data size
BYTE *dIn // IN: data buffer
576 )
577 {
BYTE *pIv;
BYTE tmp[16];
int i;
BYTE *pT;
SM4_KEY Sm4Key;
INT32 dSize; 584
585 pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); 586
587 if(dInSize == 0)
588 return CRYPT_SUCCESS; 589
590 pAssert(dInSize <= INT32_MAX);
591 dSize = (INT32)dInSize; 592
593 // Create SM4 encryption key schedule
594 if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0)
595 FAIL(FATAL_ERROR_INTERNAL); 596
597 for(; dSize > 0; dSize -= 16)
598 {
599 // Encrypt the IV into the temp buffer
600 SM4_encrypt(iv, tmp, &Sm4Key);
601 pT = tmp;
602 pIv = iv;
603 for(i = (dSize < 16) ? dSize : 16; i > 0; i--) 604 // Copy the current cipher text to IV, XOR
605 // with the temp buffer and put into the output
606 *dOut++ = *pT++ ^ (*pIv++ = *dIn++);
607 }
608 // If the inner loop (i loop) was smaller than 16, then dSize 609 // would have been smaller than 16 and it is now negative 610 // If it is negative, then it indicates how may fill bytes 611 // are needed to pad out the IV for the next round.
612 for(; dSize < 0; dSize++)
613 *iv++ = 0;
614
615 return CRYPT_SUCCESS;
616 }
This function performs SM4 encryption/decryption in CTR chain mode. The dIn buffer is encrypted into dOut. The input iv buffer is assumed to have a size equal to the SM4 block size (16 bytes). The iv will be incremented by the number of blocks (full and partial) that were encrypted.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
617 | LIB_EXPORT CRYPT_RESULT | |
618 | _cpri SM4EncryptCTR( | |
619 | BYTE *dOut, // OUT: the encrypted data | |
620 | UINT32 keySizeInBits, // IN: key size in bit | |
621 | BYTE *key, // IN: key buffer. The size of this buffer | in |
622 | // bytes is (keySizeInBits + 7) / 8 | |
623 | BYTE *iv, // IN/OUT: IV for decryption. | |
624 | UINT32 dInSize, // IN: data size | |
625 | BYTE *dIn // IN: data buffer | |
626 | ) | |
627 | { | |
628 | BYTE tmp[16]; | |
629 | BYTE *pT; | |
630 | SM4_KEY Sm4Key; | |
631 | int i; | |
632 | INT32 dSize; | |
633 | ||
634 | pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); | |
635 | ||
636 | if(dInSize == 0) | |
637 | return CRYPT_SUCCESS; | |
638 | ||
639 | pAssert(dInSize <= INT32_MAX); | |
640 | dSize = (INT32)dInSize; | |
641 | ||
642 | // Create SM4 encryption schedule | |
643 | if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0) | |
644 | FAIL(FATAL_ERROR_INTERNAL); | |
645 | ||
646 | for(; dSize > 0; dSize--) | |
647 | { | |
648 | // Encrypt the current value of the IV(counter) | |
649 | SM4_encrypt(iv, (BYTE *)tmp, &Sm4Key); | |
650 | ||
651 | //increment the counter | |
652 | for(i = 0; i < 16; i++) | |
653 | if((iv[i] += 1) != 0) | |
654 | break; | |
655 | ||
656 | // XOR the encrypted counter value with input and put into output | |
657 | pT = tmp; | |
658 | for(i = (dSize < 16) ? dSize : 16; i > 0; i--) | |
659 | *dOut++ = *dIn++ ^ *pT++; | |
660 | } | |
661 | return CRYPT_SUCCESS; | |
662 | } |
Counter mode decryption uses the same algorithm as encryption. The _cpri__SM4DecryptCTR() function is implemented as a macro call to _cpri SM4EncryptCTR(). (skip)
663 //% #define _cpri SM4DecryptCTR(dOut, keySize, key, iv, dInSize, dIn) \ 664 //% _cpri SM4EncryptCTR( \
665 //% ((BYTE *)dOut), \
666 //% ((UINT32)keySize), \
667 //% ((BYTE *)key), \
668 //% ((BYTE *)iv), \
669 //% ((UINT32)dInSize), \
670 //% ((BYTE *)dIn) \
671 //% )
672 //%
673 // The //% is used by the prototype extraction program to cause it to include the 674 // line in the prototype file after removing the //%. Need an extra line with
nothing on it so that a blank line will separate this macro from the next definition.
SM4 encryption in ECB mode. The data buffer is modified to contain the cipher text.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
675 LIB_EXPORT CRYPT_RESULT
676 _cpri SM4EncryptECB(
677 BYTE *dOut, // OUT: encrypted data 678 UINT32 keySizeInBits, // IN: key size in bit
679 BYTE *key, // IN: key buffer. The size of this buffer in 680 // bytes is (keySizeInBits + 7) / 8
681 UINT32 dInSize, // IN: data size
682 BYTE *dIn // IN: clear text buffer 683 )
684 {
685 SM4_KEY Sm4Key;
686 INT32 dSize;
687
688 pAssert(dOut != NULL && key != NULL && dIn != NULL); 689
690 if(dInSize == 0)
691 return CRYPT_SUCCESS;
692
693 pAssert(dInSize <= INT32_MAX); 694 dSize = (INT32)dInSize;
695
696 // For ECB, the data size must be an even multiple of the 697 // cipher block size
698 if((dSize % 16) != 0)
699 return CRYPT_PARAMETER;
700 // Create SM4 encrypting key schedule
701 if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0) 702 FAIL(FATAL_ERROR_INTERNAL);
703
704 for(; dSize > 0; dSize -= 16)
705 {
706 SM4_encrypt(dIn, dOut, &Sm4Key);
707 dIn = &dIn[16];
708 dOut = &dOut[16]; 709 }
710 return CRYPT_SUCCESS;
711 }
This function performs SM4 decryption using ECB (not recommended). The cipher text dIn is decrypted into dOut.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
712 | LIB_EXPORT CRYPT_RESULT | |
713 | _cpri SM4DecryptECB( | |
714 | BYTE *dOut, // OUT: the clear text data | |
715 | UINT32 keySizeInBits, // IN: key size in bit | |
716 | BYTE *key, // IN: key buffer. The size of | this buffer in |
717 | // bytes is (keySizeInBits | + 7) / 8 |
718 | UINT32 dInSize, // IN: data size | |
719 | BYTE *dIn // IN: cipher text buffer | |
720 | ) | |
721 | { | |
722 | SM4_KEY Sm4Key; | |
723 | INT32 dSize; | |
724 | ||
725 | pAssert(dOut != NULL && key != NULL && dIn != NULL); | |
726 | ||
727 | if(dInSize == 0) | |
728 | return CRYPT_SUCCESS; | |
729 | ||
730 | pAssert(dInSize <= INT32_MAX); | |
731 | dSize = (INT32)dInSize; | |
732 | ||
733 | // For ECB, the data size must be an even multiple of the | |
734 | // cipher block size | |
735 | if((dSize % 16) != 0) | |
736 | return CRYPT_PARAMETER; | |
737 | ||
738 | // Create SM4 decryption key schedule | |
739 | if (SM4_set_decrypt_key(key, keySizeInBits, &Sm4Key) != 0) | |
740 | FAIL(FATAL_ERROR_INTERNAL); | |
741 | ||
742 | for(; dSize > 0; dSize -= 16) | |
743 | { | |
744 | SM4_decrypt(dIn, dOut, &Sm4Key); | |
745 | dIn = &dIn[16]; | |
746 | dOut = &dOut[16]; | |
747 | } | |
748 | return CRYPT_SUCCESS; | |
749 | } | |
This function performs SM4 encryption/decryption in OFB chain mode. The | dIn buffer is modified to | |
contain the encrypted/decrypted text. |
The input iv buffer is assumed to have a size equal to the block size (16 bytes). The returned value of iv
will be the nth encryption of the IV, where n is the number of blocks (full or partial) in the data stream.
Return Value | Meaning |
CRYPT_SUCCESS | no non-fatal errors |
750 LIB_EXPORT CRYPT_RESULT
751 _cpri SM4EncryptOFB(
752 BYTE *dOut, // OUT: the encrypted/decrypted data 753 UINT32 keySizeInBits, // IN: key size in bit
754 BYTE *key, // IN: key buffer. The size of this buffer in 755 // bytes is (keySizeInBits + 7) / 8
756 BYTE *iv, // IN/OUT: IV for decryption. The size of this 757 // buffer is 16 byte
758 | UINT32 dInSize, // IN: data size | |
759 | BYTE *dIn // IN: data buffer | |
760 | ) | |
761 | { | |
762 | BYTE *pIv; | |
763 | SM4_KEY Sm4Key; | |
764 | INT32 dSize; | |
765 | int i; | |
766 | ||
767 | pAssert(dOut != NULL && key != NULL && iv != NULL && dIn != NULL); | |
768 | ||
769 | if(dInSize == 0) | |
770 | return CRYPT_SUCCESS; | |
771 | ||
772 | pAssert(dInSize <= INT32_MAX); | |
773 | dSize = (INT32)dInSize; | |
774 | ||
775 | // Create SM4 key schedule | |
776 | if (SM4_set_encrypt_key(key, keySizeInBits, &Sm4Key) != 0) | |
777 | FAIL(FATAL_ERROR_INTERNAL); | |
778 | ||
779 | // This is written so that dIn and dOut may be the same | |
780 | ||
781 | for(; dSize > 0; dSize -= 16) | |
782 | { | |
783 | // Encrypt the current value of the "IV" | |
784 | SM4_encrypt(iv, iv, &Sm4Key); | |
785 | ||
786 | // XOR the encrypted IV into dIn to create the cipher text (dOut) | |
787 | pIv = iv; | |
788 | for(i = (dSize < 16) ? dSize : 16; i > 0; i--) | |
789 | *dOut++ = (*pIv++ ^ *dIn++); | |
790 | } | |
791 | return CRYPT_SUCCESS; | |
792 | } |
B.11.5.10._cpri__SM4DecryptOFB()
OFB encryption and decryption use the same algorithms for both. The _cpri__SM4DecryptOFB() function is implemented as a macro call to _cpri SM4EncrytOFB(). (skip)
793 | //%#define | _cpri SM4DecryptOFB(dOut,keySizeInBits, key, iv, dInSize, dIn) \ | ||
794 | //% | _cpri SM4EncryptOFB ( \ | ||
795 | //% | ((BYTE *)dOut), | \ | |
796 | //% | ((UINT32)keySizeInBits), | \ | |
797 | //% | ((BYTE *)key), | \ | |
798 | //% | ((BYTE *)iv), | \ | |
799 | //% | ((UINT32)dInSize), | \ | |
800 | //% | ((BYTE *)dIn) | \ | |
801 | //% | ) | ||
802 | //% | |||
803 | #endif | //% TPM_ALG_SM4 |
This file contains implementation of crypto primitives for RSA. This is a simulator of a crypto engine. Vendors may replace the implementation in this file with their own library functions.
Integer format: the big integers passed in/out to the function interfaces in this library adopt the same format used in TPM 2.0 specification: Integer values are considered to be an array of one or more bytes. The byte at offset zero within the array is the most significant byte of the integer. The interface uses TPM2B as a big number format for numeric values passed to/from CryptUtil().
#include "OsslCryptoEngine.h"
#ifdef TPM_ALG_RSA
Local Functions B.12.1.3.1. RsaPrivateExponent()
This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus and one of the primes.
The results are returned in the key->private structure. The size of that structure is expanded to hold the private exponent. If the computed value is smaller than the public modulus, the private exponent is de- normalized.
Return Value | Meaning |
CRYPT_SUCCESS | private exponent computed |
CRYPT_PARAMETER | prime is not half the size of the modulus, or the modulus is not evenly divisible by the prime, or no private exponent could be computed from the input parameters |
static CRYPT_RESULT
RsaPrivateExponent(
RSA_KEY *key // IN: the key to augment with the private
// exponent
7 )
8 {
BN_CTX *context;
BIGNUM *bnD;
BIGNUM *bnN;
BIGNUM *bnP;
BIGNUM *bnE;
BIGNUM *bnPhi;
BIGNUM *bnQ;
BIGNUM *bnQr;
UINT32 fill; 18
19 CRYPT_RESULT retVal = CRYPT_SUCCESS; // Assume success 20
21 pAssert(key != NULL && key->privateKey != NULL && key->publicKey != NULL); 22
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnE = BN_CTX_get(context);
bnD = BN_CTX_get(context);
bnN = BN_CTX_get(context);
bnP = BN_CTX_get(context);
bnPhi = BN_CTX_get(context);
bnQ = BN_CTX_get(context);
bnQr = BN_CTX_get(context); 34
if(bnQr == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 37
// Assume the size of the public key value is within range
pAssert(key->publicKey->size <= MAX_RSA_KEY_BYTES); 40
if( BN_bin2bn(key->publicKey->buffer, key->publicKey->size, bnN) == NULL
|| BN_bin2bn(key->privateKey->buffer, key->privateKey->size, bnP) == NULL) 43
44 FAIL(FATAL_ERROR_INTERNAL); 45
// If P size is not 1/2 of n size, then this is not a valid value for this
// implementation. This will also catch the case were P is input as zero.
// This generates a return rather than an assert because the key being loaded
// might be SW generated and wrong.
if(BN_num_bits(bnP) < BN_num_bits(bnN)/2) 51 {
retVal = CRYPT_PARAMETER;
goto Cleanup; 54 }
// Get q = n/p;
if (BN_div(bnQ, bnQr, bnN, bnP, context) != 1)
FAIL(FATAL_ERROR_INTERNAL); 58
// If there is a remainder, then this is not a valid n
if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP)) 61 {
retVal = CRYPT_PARAMETER; // problem may be recoverable
goto Cleanup; 64 }
// Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1
if( BN_copy(bnPhi, bnN) == NULL
|| !BN_sub(bnPhi, bnPhi, bnP)
|| !BN_sub(bnPhi, bnPhi, bnQ)
|| !BN_add_word(bnPhi, 1))
FAIL(FATAL_ERROR_INTERNAL); 71
// Compute the multiplicative inverse
BN_set_word(bnE, key->exponent);
if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL) 75 {
// Going to assume that the error is caused by a bad
// set of parameters. Specifically, an exponent that is
// not compatible with the primes. In an implementation that
// has better visibility to the error codes, this might be
// refined so that failures in the library would return
// a more informative value. Should not assume here that
// the error codes will remain unchanged. 83
retVal = CRYPT_PARAMETER;
goto Cleanup; 86 }
87
fill = key->publicKey->size - BN_num_bytes(bnD);
BN_bn2bin(bnD, &key->privateKey->buffer[fill]);
memset(key->privateKey->buffer, 0, fill); 91
// Change the size of the private key so that it is known to contain
// a private exponent rather than a prime.
key->privateKey->size = key->publicKey->size; 95
Cleanup:
BN_CTX_end(context);
BN_CTX_free(context);
return retVal;
100 }
This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus and one of the primes or two primes.
If both primes are provided, the public modulus is computed. If only one prime is provided, the second prime is computed. In either case, a private exponent is produced and placed in d.
If no modular inverse exists, then CRYPT_PARAMETER is returned.
Return Value | Meaning |
CRYPT_SUCCESS | private exponent (d) was generated |
CRYPT_PARAMETER | one or more parameters are invalid |
101 | LIB_EXPORT CRYPT_RESULT | |
102 | _cpri TestKeyRSA( | |
103 | TPM2B *d, // OUT: the address to receive the private | |
104 | // exponent | |
105 | UINT32 exponent, // IN: the public modulu | |
106 | TPM2B *publicKey, // IN/OUT: an input if only one prime is | |
107 | // provided. an output if both primes | are |
108 | // provided | |
109 | TPM2B *prime1, // IN: a first prime | |
110 | TPM2B *prime2 // IN: an optional second prime | |
111 | ) | |
112 | { | |
113 | BN_CTX *context; | |
114 | BIGNUM *bnD; | |
115 | BIGNUM *bnN; | |
116 | BIGNUM *bnP; | |
117 | BIGNUM *bnE; | |
118 | BIGNUM *bnPhi; | |
119 | BIGNUM *bnQ; | |
120 | BIGNUM *bnQr; | |
121 | UINT32 fill; | |
122 | ||
123 | CRYPT_RESULT retVal = CRYPT_SUCCESS; // Assume success | |
124 | ||
125 | pAssert(publicKey != NULL && prime1 != NULL); | |
126 | // Make sure that the sizes are within range | |
127 | pAssert( prime1->size <= MAX_RSA_KEY_BYTES/2 | |
128 | && publicKey->size <= MAX_RSA_KEY_BYTES); | |
129 | pAssert( prime2 == NULL || prime2->size < MAX_RSA_KEY_BYTES/2); | |
130 | ||
131 | if(publicKey->size/2 != prime1->size) | |
132 | return CRYPT_PARAMETER; | |
133 | ||
134 | context = BN_CTX_new(); | |
135 | if(context == NULL) | |
136 | FAIL(FATAL_ERROR_ALLOCATION); | |
137 | BN_CTX_start(context); |
138 | bnE = BN_CTX_get(context); // public exponent (e) | |
139 | bnD = BN_CTX_get(context); // private exponent (d) | |
140 | bnN = BN_CTX_get(context); // public modulus (n) | |
141 | bnP = BN_CTX_get(context); // prime1 (p) | |
142 | bnPhi = BN_CTX_get(context); // (p-1)(q-1) | |
143 | bnQ = BN_CTX_get(context); // prime2 (q) | |
144 | bnQr = BN_CTX_get(context); // n mod p | |
145 | ||
146 | if(bnQr == NULL) | |
147 | FAIL(FATAL_ERROR_ALLOCATION); | |
148 | ||
149 | if(BN_bin2bn(prime1->buffer, prime1->size, bnP) == NULL) | |
150 | FAIL(FATAL_ERROR_INTERNAL); | |
151 | ||
152 | // If prime2 is provided, then compute n | |
153 | if(prime2 != NULL) | |
154 | { | |
155 | // Two primes provided so use them to compute n | |
156 | if(BN_bin2bn(prime2->buffer, prime2->size, bnQ) == NULL) | |
157 | FAIL(FATAL_ERROR_INTERNAL); | |
158 | ||
159 | // Make sure that the sizes of the primes are compatible | |
160 | if(BN_num_bits(bnQ) != BN_num_bits(bnP)) | |
161 | { | |
162 | retVal = CRYPT_PARAMETER; | |
163 | goto Cleanup; | |
164 | } | |
165 | // Multiply the primes to get the public modulus | |
166 | ||
167 | if(BN_mul(bnN, bnP, bnQ, context) != 1) | |
168 | FAIL(FATAL_ERROR_INTERNAL); | |
169 | ||
170 | // if the space provided for the public modulus is large | enough, |
171 | // save the created value | |
172 | if(BN_num_bits(bnN) != (publicKey->size * 8)) | |
173 | { | |
174 | retVal = CRYPT_PARAMETER; | |
175 | goto Cleanup; | |
176 | } | |
177 | BN_bn2bin(bnN, publicKey->buffer); | |
178 | } | |
179 | else | |
180 | { |
// One prime provided so find the second prime by division
BN_bin2bn(publicKey->buffer, publicKey->size, bnN); 183
// Get q = n/p;
if(BN_div(bnQ, bnQr, bnN, bnP, context) != 1)
FAIL(FATAL_ERROR_INTERNAL); 187
// If there is a remainder, then this is not a valid n
if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP))
190 {
retVal = CRYPT_PARAMETER; // problem may be recoverable
goto Cleanup;
193 }
194 }
// Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1
BN_copy(bnPhi, bnN);
BN_sub(bnPhi, bnPhi, bnP);
BN_sub(bnPhi, bnPhi, bnQ);
BN_add_word(bnPhi, 1);
// Compute the multiplicative inverse
BN_set_word(bnE, exponent);
if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL)
203 {
// Going to assume that the error is caused by a bad set of parameters.
// Specifically, an exponent that is not compatible with the primes.
// In an implementation that has better visibility to the error codes,
// this might be refined so that failures in the library would return
// a more informative value.
// Do not assume that the error codes will remain unchanged.
retVal = CRYPT_PARAMETER;
goto Cleanup;
212 }
// Return the private exponent.
// Make sure it is normalized to have the correct size.
d->size = publicKey->size;
fill = d->size - BN_num_bytes(bnD);
BN_bn2bin(bnD, &d->buffer[fill]);
memset(d->buffer, 0, fill);
Cleanup:
BN_CTX_end(context);
BN_CTX_free(context);
return retVal;
223 }
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).
Return Value | Meaning |
CRYPT_SUCCESS | encryption complete |
CRYPT_PARAMETER | number to exponentiate is larger than the modulus |
static CRYPT_RESULT
RSAEP (
UINT32 dInOutSize, // OUT size of the encrypted block
BYTE *dInOut, // OUT: the encrypted data
RSA_KEY *key // IN: the key to use
229 )
230 {
UINT32 e;
BYTE exponent[4];
CRYPT_RESULT retVal; 234
235 e = key->exponent;
236 if(e == 0)
e = RSA_DEFAULT_PUBLIC_EXPONENT;
UINT32_TO_BYTE_ARRAY(e, exponent); 239
240 //!!! Can put check for test of RSA here 241
retVal = _math ModExp(dInOutSize, dInOut, dInOutSize, dInOut, 4, exponent,
key->publicKey->size, key->publicKey->buffer); 244
// Exponentiation result is stored in-place, thus no space shortage is possible.
pAssert(retVal != CRYPT_UNDERFLOW); 247
248 return retVal;
249 }
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.
Return Value | Meaning |
CRYPT_SUCCESS | decryption succeeded |
CRYPT_PARAMETER | the value to decrypt is larger than the modulus |
static CRYPT_RESULT
RSADP (
UINT32 dInOutSize, // IN/OUT: size of decrypted data
BYTE *dInOut, // IN/OUT: the decrypted data
RSA_KEY *key // IN: the key
255 )
256 {
257 CRYPT_RESULT retVal; 258
259 //!!! Can put check for RSA tested here 260
// Make sure that the pointers are provided and that the private key is present
// If the private key is present it is assumed to have been created by
// so is presumed good _cpri PrivateExponent
pAssert(key != NULL && dInOut != NULL &&
key->publicKey->size == key->publicKey->size); 266
// make sure that the value to be decrypted is smaller than the modulus
// note: this check is redundant as is also performed by _math ModExp()
// which is optimized for use in RSA operations
if(_math uComp(key->publicKey->size, key->publicKey->buffer,
dInOutSize, dInOut) <= 0)
return CRYPT_PARAMETER; 273
// _math ModExp can return CRYPT_PARAMTER or CRYPT_UNDERFLOW but actual
// underflow is not possible because everything is in the same buffer.
retVal = _math ModExp(dInOutSize, dInOut, dInOutSize, dInOut,
key->privateKey->size, key->privateKey->buffer,
key->publicKey->size, key->publicKey->buffer); 279
// Exponentiation result is stored in-place, thus no space shortage is possible.
pAssert(retVal != CRYPT_UNDERFLOW); 282
283 return retVal;
284 }
This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must equal the size of the modulus
Return Value | Meaning |
CRYPT_SUCCESS | encode successful |
CRYPT_PARAMETER | hashAlg is not valid |
CRYPT_FAIL | message size is too large |
285 | static CRYPT_RESULT | ||
286 | OaepEncode( | ||
287 | UINT32 paddedSize, | // | IN: pad value size |
288 | BYTE *padded, | // | OUT: the pad data |
289 | TPM_ALG_ID hashAlg, | // | IN: algorithm to use for padding |
290 | const char *label, | // | IN: null-terminated string (may be NULL) |
UINT32 messageSize, // IN: the message size
BYTE *message // IN: the message being padded
#ifdef TEST_RSA //
, BYTE *testSeed // IN: optional seed used for testing.
#endif // TEST_RSA //
296 )
297 {
UINT32 padLen;
UINT32 dbSize;
UINT32 i;
BYTE mySeed[MAX_DIGEST_SIZE];
BYTE *seed = mySeed;
INT32 hLen = _cpri GetDigestSize(hashAlg);
BYTE mask[MAX_RSA_KEY_BYTES];
BYTE *pp;
BYTE *pm;
UINT32 lSize = 0;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 309
310 pAssert(padded != NULL && message != NULL); 311
// A value of zero is not allowed because the KDF can't produce a result
// if the digest size is zero.
if(hLen <= 0)
return CRYPT_PARAMETER; 316
// If a label is provided, get the length of the string, including the
// terminator
if(label != NULL)
lSize = (UINT32)strlen(label) + 1; 321
// Basic size check
// messageSize <= k 2hLen 2
if(messageSize > paddedSize - 2 * hLen - 2)
return CRYPT_FAIL; 326
// Hash L even if it is null
// Offset into padded leaving room for masked seed and byte of zero
pp = &padded[hLen + 1];
retVal = _cpri HashBlock(hashAlg, lSize, (BYTE *)label, hLen, pp); 331
// concatenate PS of k mLen 2hLen 2
padLen = paddedSize - messageSize - (2 * hLen) - 2;
memset(&pp[hLen], 0, padLen);
pp[hLen+padLen] = 0x01;
padLen += 1;
memcpy(&pp[hLen+padLen], message, messageSize); 338
// The total size of db = hLen + pad + mSize;
dbSize = hLen+padLen+messageSize; 341
// If testing, then use the provided seed. Otherwise, use values
// from the RNG
#ifdef TEST_RSA
if(testSeed != NULL)
seed = testSeed;
else
#endif // TEST_RSA
_cpri GenerateRandom(hLen, mySeed); 350
// mask = MGF1 (seed, nSize hLen 1)
if((retVal = _cpri MGF1(dbSize, mask, hashAlg, hLen, seed)) < 0)
return retVal; // Don't expect an error because hash size is not zero
// was detected in the call to _cpri HashBlock() above. 355
356 // Create the masked db
357 | pm = mask; | |
358 | for(i = dbSize; i > 0; i--) | |
359 | *pp++ ^= *pm++; | |
360 | pp = &padded[hLen + 1]; | |
361 | ||
362 | // Run the masked data through MGF1 | |
363 | if((retVal = _cpri MGF1(hLen, &padded[1], hashAlg, dbSize, pp)) < 0) | |
364 | return retVal; // Don't expect zero here as the only case for zero | |
365 | // was detected in the call to _cpri HashBlock() above. | |
366 | ||
367 | // Now XOR the seed to create masked seed | |
368 | pp = &padded[1]; | |
369 | pm = seed; | |
370 | for(i = hLen; i > 0; i--) | |
371 | *pp++ ^= *pm++; | |
372 | ||
373 | // Set the first byte to zero | |
374 | *padded = 0x00; | |
375 | return CRYPT_SUCCESS; | |
376 | } |
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 CRYPT_NO_RESULTS.
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 CRYPT_FAIL.
Return Value | Meaning |
CRYPT_SUCCESS | decode complete |
CRYPT_PARAMETER | the value to decode was larger than the modulus |
CRYPT_FAIL | the padding is wrong or the buffer to receive the results is too small |
static CRYPT_RESULT
OaepDecode(
UINT32 *dataOutSize, // IN/OUT: the recovered data size
BYTE *dataOut, // OUT: the recovered data
TPM_ALG_ID hashAlg, // IN: algorithm to use for padding
const char *label, // IN: null-terminated string (may be NULL)
UINT32 paddedSize, // IN: the size of the padded data
BYTE *padded // IN: the padded data
385 )
386 {
UINT32 dSizeSave;
UINT32 i;
BYTE seedMask[MAX_DIGEST_SIZE];
INT32 hLen = _cpri GetDigestSize(hashAlg); 391
BYTE mask[MAX_RSA_KEY_BYTES];
BYTE *pp;
BYTE *pm;
UINT32 lSize = 0;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 397
// Unknown hash
pAssert(hLen > 0 && dataOutSize != NULL && dataOut != NULL && padded != NULL); 400
401 // If there is a label, get its size including the terminating 0x00
402 if(label != NULL)
403 lSize = (UINT32)strlen(label) + 1; 404
405 // Set the return size to zero so that it doesn't have to be done on each
406 // failure
407 dSizeSave = *dataOutSize;
408 *dataOutSize = 0; 409
410 // Strange size (anything smaller can't be an OAEP padded block)
411 // Also check for no leading 0
412 if(paddedSize < (unsigned)((2 * hLen) + 2) || *padded != 0)
413 return CRYPT_FAIL; 414
415 // Use the hash size to determine what to put through MGF1 in order
416 // to recover the seedMask
417 if((retVal = _cpri MGF1(hLen, seedMask, hashAlg,
418 paddedSize-hLen-1, &padded[hLen+1])) < 0)
419 return retVal; 420
421 // Recover the seed into seedMask
422 pp = &padded[1];
423 pm = seedMask;
424 for(i = hLen; i > 0; i--) 425 *pm++ ^= *pp++;
426
427 // Use the seed to generate the data mask
428 if((retVal = _cpri MGF1(paddedSize-hLen-1, mask, hashAlg,
429 hLen, seedMask)) < 0)
430 return retVal; 431
432 // Use the mask generated from seed to recover the padded data
433 pp = &padded[hLen+1];
434 pm = mask;
435 for(i = paddedSize-hLen-1; i > 0; i--) 436 *pm++ ^= *pp++;
437
438 // Make sure that the recovered data has the hash of the label
439 // Put trial value in the seed mask
440 if((retVal=_cpri HashBlock(hashAlg, lSize,(BYTE *)label, hLen, seedMask)) < 0)
441 return retVal; 442
443 if(memcmp(seedMask, mask, hLen) != 0)
444 return CRYPT_FAIL; 445
446 // find the start of the data
447 pm = &mask[hLen];
448 for(i = paddedSize-(2*hLen)-1; i > 0; i--)
449 {
450 if(*pm++ != 0)
451 break;
452 }
453 if(i == 0)
454 return CRYPT_PARAMETER; 455
456 // pm should be pointing at the first part of the data
457 | // and i is one greater than the number of bytes to move | |
458 | i--; | |
459 | if(i > dSizeSave) | |
460 | { | |
461 | // Restore dSize | |
462 | *dataOutSize = dSizeSave; | |
463 | return CRYPT_FAIL; | |
464 | } | |
465 | memcpy(dataOut, pm, i); | |
466 | *dataOutSize = i; | |
467 | return CRYPT_SUCCESS; | |
468 | } |
This function performs the encoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1
Return Value | Meaning |
CRYPT_SUCCESS | data encoded |
CRYPT_PARAMETER | message size is too large |
static CRYPT_RESULT
RSAES_PKSC1v1_5Encode(
UINT32 paddedSize, // IN: pad value size
BYTE *padded, // OUT: the pad data
UINT32 messageSize, // IN: the message size
BYTE *message // IN: the message being padded
475 )
476 {
477 UINT32 ps = paddedSize - messageSize - 3;
478 if(messageSize > paddedSize - 11)
479 return CRYPT_PARAMETER; 480
481 // move the message to the end of the buffer
482 memcpy(&padded[paddedSize - messageSize], message, messageSize); 483
484 // Set the first byte to 0x00 and the second to 0x02
485 *padded = 0;
486 padded[1] = 2; 487
488 // Fill with random bytes
489 _cpri GenerateRandom(ps, &padded[2]); 490
491 // Set the delimiter for the random field to 0
492 padded[2+ps] = 0; 493
494 // Now, the only messy part. Make sure that all the ps bytes are non-zero
495 // In this implementation, use the value of the current index
496 for(ps++; ps > 1; ps--)
497 {
498 if(padded[ps] == 0)
499 padded[ps] = 0x55; // In the < 0.5% of the cases that the random
500 // value is 0, just pick a value to put into
501 // the spot.
502 }
503 return CRYPT_SUCCESS;
504 }
This function performs the decoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1
Return Value | Meaning |
CRYPT_SUCCESS | decode successful |
CRYPT_FAIL | decoding error or results would no fit into provided buffer |
static CRYPT_RESULT
RSAES_Decode(
UINT32 *messageSize, // IN/OUT: recovered message size
BYTE *message, // OUT: the recovered message
UINT32 codedSize, // IN: the encoded message size
BYTE *coded // IN: the encoded message
511 )
512 | { | |
513 | BOOL fail = FALSE; | |
514 | UINT32 ps; | |
515 | ||
516 | fail = (codedSize < 11); | |
517 | fail |= (coded[0] != 0x00) || (coded[1] != 0x02); | |
518 | for(ps = 2; ps < codedSize; ps++) | |
519 | { | |
520 | if(coded[ps] == 0) | |
521 | break; | |
522 | } | |
523 | ps++; | |
524 | ||
525 | // Make sure that ps has not gone over the end and that there are at least 8 | |
526 | // bytes of pad data. | |
527 | fail |= ((ps >= codedSize) || ((ps-2) < 8)); | |
528 | if((*messageSize < codedSize - ps) || fail) | |
529 | return CRYPT_FAIL; | |
530 | ||
531 | *messageSize = codedSize - ps; | |
532 | memcpy(message, &coded[ps], codedSize - ps); | |
533 | return CRYPT_SUCCESS; | |
534 | } | |
This function creates an encoded block of data that is the size of modulus. The function uses maximum salt size that will fit in the encoded block. | the |
Return Value | Meaning |
CRYPT_SUCCESS | encode successful |
CRYPT_PARAMETER | hashAlg is not a supported hash algorithm |
static CRYPT_RESULT
PssEncode (
UINT32 eOutSize, // IN: size of the encode data buffer
BYTE *eOut, // OUT: encoded data buffer
TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding
UINT32 hashInSize, // IN: size of digest to encode
BYTE *hashIn // IN: the digest
#ifdef TEST_RSA //
, BYTE *saltIn // IN: optional parameter for testing
#endif // TEST_RSA //
545 )
546 {
INT32 hLen = _cpri GetDigestSize(hashAlg);
BYTE salt[MAX_RSA_KEY_BYTES - 1];
UINT16 saltSize;
BYTE *ps = salt;
CRYPT_RESULT retVal;
UINT16 mLen;
CPRI_HASH_STATE hashState; 554
555 // These are fatal errors indicating bad TPM firmware
556 pAssert(eOut != NULL && hLen > 0 && hashIn != NULL ); 557
558 // Get the size of the mask
559 mLen = (UINT16)(eOutSize - hLen - 1); 560
561 // Maximum possible salt size is mask length - 1
562 saltSize = mLen - 1; 563
564 // Use the maximum salt size allowed by FIPS 186-4
565 if(saltSize > hLen)
566 saltSize = (UINT16)hLen; 567
568 //using eOut for scratch space
569 // Set the first 8 bytes to zero
570 memset(eOut, 0, 8); 571
572 // Get set the salt
573 #ifdef TEST_RSA
574 if(saltIn != NULL)
575 {
576 saltSize = hLen;
577 memcpy(salt, saltIn, hLen);
578 }
579 else
580 #endif // TEST_RSA
581 _cpri GenerateRandom(saltSize, salt); 582
// Create the hash of the pad || input hash || salt
_cpri StartHash(hashAlg, FALSE, &hashState);
_cpri UpdateHash(&hashState, 8, eOut);
_cpri UpdateHash(&hashState, hashInSize, hashIn);
_cpri UpdateHash(&hashState, saltSize, salt);
_cpri CompleteHash(&hashState, hLen, &eOut[eOutSize - hLen - 1]); 589
590 // Create a mask
591 if((retVal = _cpri MGF1(mLen, eOut, hashAlg, hLen, &eOut[mLen])) < 0)
592 {
593 // Currently _cpri MGF1 is not expected to return a CRYPT_RESULT error.
594 pAssert(0);
595 }
596 // Since this implementation uses key sizes that are all even multiples of
597 // 8, just need to make sure that the most significant bit is CLEAR 598 eOut[0] &= 0x7f;
599
600 // Before we mess up the eOut value, set the last byte to 0xbc 601 eOut[eOutSize - 1] = 0xbc;
602
603 // XOR a byte of 0x01 at the position just before where the salt will be XOR'ed 604 eOut = &eOut[mLen - saltSize - 1];
605 *eOut++ ^= 0x01;
606
607 // XOR the salt data into the buffer 608 for(; saltSize > 0; saltSize--)
609 *eOut++ ^= *ps++;
610
611 // and we are done
612 return CRYPT_SUCCESS;
613 }
This function checks that the PSS encoded block was built from the provided digest. If the check is successful, CRYPT_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.
Return Value | Meaning |
CRYPT_SUCCESS | decode successful |
CRYPT_SCHEME | hashAlg is not a supported hash algorithm |
CRYPT_FAIL | decode operation failed |
614 static CRYPT_RESULT
615 PssDecode(
616 TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding 617 UINT32 dInSize, // IN: size of the digest to compare
618 BYTE *dIn, // In: the digest to compare 619 UINT32 eInSize, // IN: size of the encoded data 620 BYTE *eIn, // IN: the encoded data
621 UINT32 saltSize // IN: the expected size of the salt 622 )
623 {
624 INT32 hLen = _cpri GetDigestSize(hashAlg); 625 BYTE mask[MAX_RSA_KEY_BYTES];
626 BYTE *pm = mask;
627 BYTE pad[8] = {0};
628 UINT32 i;
629 UINT32 mLen;
630 BOOL fail = FALSE;
631 CRYPT_RESULT retVal;
632 CPRI_HASH_STATE hashState;
633
634 // These errors are indicative of failures due to programmer error 635 pAssert(dIn != NULL && eIn != NULL);
636
637 // check the hash scheme
638 if(hLen == 0)
639 return CRYPT_SCHEME;
640
641 // most significant bit must be zero 642 fail = ((eIn[0] & 0x80) != 0);
643
644 // last byte must be 0xbc
645 fail |= (eIn[eInSize - 1] != 0xbc); 646
647 // Use the hLen bytes at the end of the buffer to generate a mask 648 // Doesn't start at the end which is a flag byte
649 mLen = eInSize - hLen - 1;
650 if((retVal = _cpri MGF1(mLen, mask, hashAlg, hLen, &eIn[mLen])) < 0) 651 return retVal;
652 if(retVal == 0)
653 return CRYPT_FAIL;
654
655 // Clear the MSO of the mask to make it consistent with the encoding. 656 mask[0] &= 0x7F;
657
658 // XOR the data into the mask to recover the salt. This sequence 659 // advances eIn so that it will end up pointing to the seed data 660 // which is the hash of the signature data
661 for(i = mLen; i > 0; i--) 662 *pm++ ^= *eIn++;
663
664 // Find the first byte of 0x01 after a string of all 0x00 665 for(pm = mask, i = mLen; i > 0; i--)
666 {
667 if(*pm == 0x01) 668 break;
669 else
670 fail |= (*pm++ != 0);
671 }
672 | fail |= (i == 0); | |
673 | ||
674 | // if we have failed, will continue using the entire mask as the salt value so | |
675 | // that the timing attacks will not disclose anything (I don't think that this | |
676 | // is a problem for TPM applications but, usually, we don't fail so this | |
677 | // doesn't cost anything). | |
678 | if(fail) | |
679 | { | |
680 | i = mLen; | |
681 | pm = mask; | |
682 | } | |
683 | else | |
684 | { | |
685 | pm++; | |
686 | i--; | |
687 | } | |
688 | // If the salt size was provided, then the recovered size must match | |
689 | fail |= (saltSize != 0 && i != saltSize); | |
690 | ||
691 | // i contains the salt size and pm points to the salt. Going to use the input | |
692 | // hash and the seed to recreate the hash in the lower portion of eIn. | |
693 | _cpri StartHash(hashAlg, FALSE, &hashState); | |
694 | ||
695 | // add the pad of 8 zeros | |
696 | _cpri UpdateHash(&hashState, 8, pad); | |
697 | ||
698 | // add the provided digest value | |
699 | _cpri UpdateHash(&hashState, dInSize, dIn); | |
700 | ||
701 | // and the salt | |
702 | _cpri UpdateHash(&hashState, i, pm); | |
703 | ||
704 | // get the result | |
705 | retVal = _cpri CompleteHash(&hashState, MAX_DIGEST_SIZE, mask); | |
706 | ||
707 | // retVal will be the size of the digest or zero. If not equal to the indicated | |
708 | // digest size, then the signature doesn't match | |
709 | fail |= (retVal != hLen); | |
710 | fail |= (memcmp(mask, eIn, hLen) != 0); | |
711 | if(fail) | |
712 | return CRYPT_FAIL; | |
713 | else | |
714 | return CRYPT_SUCCESS; | |
715 | } |
Encode a message using PKCS1v1().5 method.
Return Value | Meaning |
CRYPT_SUCCESS | encode complete |
CRYPT_SCHEME | hashAlg is not a supported hash algorithm |
CRYPT_PARAMETER | eOutSize is not large enough or hInSize does not match the digest size of hashAlg |
716 static CRYPT_RESULT
717 RSASSA_Encode(
718 UINT32 eOutSize, // IN: the size of the resulting block 719 BYTE *eOut, // OUT: the encoded block
720 TPM_ALG_ID hashAlg, // IN: hash algorithm for PKSC1v1_5 721 UINT32 hInSize, // IN: size of hash to be signed 722 BYTE *hIn // IN: hash buffer
723 | ) | |
724 | { | |
725 | BYTE *der; | |
726 | INT32 derSize = _cpri GetHashDER(hashAlg, &der); | |
727 | INT32 fillSize; | |
728 | ||
729 | pAssert(eOut != NULL && hIn != NULL); | |
730 | ||
731 | // Can't use this scheme if the algorithm doesn't have a DER string defined. | |
732 | if(derSize == 0 ) | |
733 | return CRYPT_SCHEME; | |
734 | ||
735 | // If the digest size of 'hashAl' doesn't match the input digest size, then | |
736 | // the DER will misidentify the digest so return an error | |
737 | if((unsigned)_cpri GetDigestSize(hashAlg) != hInSize) | |
738 | return CRYPT_PARAMETER; | |
739 | ||
740 | fillSize = eOutSize - derSize - hInSize - 3; | |
741 | ||
742 | // Make sure that this combination will fit in the provided space | |
743 | if(fillSize < 8) | |
744 | return CRYPT_PARAMETER; | |
745 | // Start filling | |
746 | *eOut++ = 0; // initial byte of zero | |
747 | *eOut++ = 1; // byte of 0x01 | |
748 | for(; fillSize > 0; fillSize--) | |
749 | *eOut++ = 0xff; // bunch of 0xff | |
750 | *eOut++ = 0; // another 0 | |
751 | for(; derSize > 0; derSize--) | |
752 | *eOut++ = *der++; // copy the DER | |
753 | for(; hInSize > 0; hInSize--) | |
754 | *eOut++ = *hIn++; // copy the hash | |
755 | return CRYPT_SUCCESS; | |
756 | } |
This function performs the RSASSA decoding of a signature.
Return Value | Meaning |
CRYPT_SUCCESS | decode successful |
CRYPT_FAIL | decode unsuccessful |
CRYPT_SCHEME | haslAlg is not supported |
757 static CRYPT_RESULT
758 RSASSA_Decode(
759 TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding 760 UINT32 hInSize, // IN: size of the digest to compare
761 BYTE *hIn, // In: the digest to compare 762 UINT32 eInSize, // IN: size of the encoded data 763 BYTE *eIn // IN: the encoded data
764 )
765 {
766 BOOL fail = FALSE;
767 BYTE *der;
768 INT32 derSize = _cpri GetHashDER(hashAlg, &der); 769 INT32 hashSize = _cpri GetDigestSize(hashAlg); 770 INT32 fillSize;
771
772 pAssert(hIn != NULL && eIn != NULL); 773
774 // Can't use this scheme if the algorithm doesn't have a DER string
775 | // defined or if the provided hash isn't the right size | |
776 | if(derSize == 0 || (unsigned)hashSize != hInSize) | |
777 | return CRYPT_SCHEME; | |
778 | ||
779 | // Make sure that this combination will fit in the provided space | |
780 | // Since no data movement takes place, can just walk though this | |
781 | // and accept nearly random values. This can only be called from | |
782 | // _cpri ValidateSignature() so eInSize is known to be in range. | |
783 | fillSize = eInSize - derSize - hashSize - 3; | |
784 | ||
785 | // Start checking | |
786 | fail |= (*eIn++ != 0); // initial byte of zero | |
787 | fail |= (*eIn++ != 1); // byte of 0x01 | |
788 | for(; fillSize > 0; fillSize--) | |
789 | fail |= (*eIn++ != 0xff); // bunch of 0xff | |
790 | fail |= (*eIn++ != 0); // another 0 | |
791 | for(; derSize > 0; derSize--) | |
792 | fail |= (*eIn++ != *der++); // match the DER | |
793 | for(; hInSize > 0; hInSize--) | |
794 | fail |= (*eIn++ != *hIn++); // match the hash | |
795 | if(fail) | |
796 | return CRYPT_FAIL; | |
797 | return CRYPT_SUCCESS; | |
798 | } |
Externally Accessible Functions
Function that is called to initialize the hash service. In this implementation, this function does nothing but it is called by the CryptUtilStartup() function and must be present.
799 LIB_EXPORT BOOL
800 _cpri RsaStartup(
801 void
802 )
803 {
804 return TRUE;
805 }
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 treaded 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.
Return Value | Meaning |
CRYPT_SUCCESS | encryption complete |
CRYPT_PARAMETER | cOutSize is too small (must be the size of the modulus) |
CRYPT_SCHEME | padType is not a supported scheme |
806 LIB_EXPORT CRYPT_RESULT
807 _cpri EncryptRSA(
808 UINT32 *cOutSize, // OUT: the size of the encrypted data 809 BYTE *cOut, // OUT: the encrypted data
810 RSA_KEY *key, // IN: the key to use for encryption 811 TPM_ALG_ID padType, // IN: the type of padding
812 UINT32 dInSize, // IN: the amount of data to encrypt 813 BYTE *dIn, // IN: the data to encrypt
814 TPM_ALG_ID hashAlg, // IN: in case this is needed 815 const char *label // IN: in case it is needed 816 )
817 {
818 CRYPT_RESULT retVal = CRYPT_SUCCESS;
819
820 pAssert(cOutSize != NULL); 821
822 // All encryption schemes return the same size of data 823 if(*cOutSize < key->publicKey->size)
824 return CRYPT_PARAMETER;
825 *cOutSize = key->publicKey->size; 826
827 switch (padType)
828 {
829 case TPM_ALG_NULL: // 'raw' encryption 830 {
831 // dIn can have more bytes than cOut as long as the extra bytes 832 // are zero
833 for(; dInSize > *cOutSize; dInSize--)
834 {
835 if(*dIn++ != 0)
836 return CRYPT_PARAMETER;
837
838 }
839 // If dIn is smaller than cOut, fill cOut with zeros
840 if(dInSize < *cOutSize)
841 memset(cOut, 0, *cOutSize - dInSize);
842
843 // Copy the rest of the value
844 memcpy(&cOut[*cOutSize-dInSize], dIn, dInSize);
845 // If the size of dIn is the same as cOut dIn could be larger than 846 // the modulus. If it is, then RSAEP() will catch it.
847 }
848 break;
849 case TPM_ALG_RSAES:
850 retVal = RSAES_PKSC1v1_5Encode(*cOutSize, cOut, dInSize, dIn); 851 break;
852 case TPM_ALG_OAEP:
853 retVal = OaepEncode(*cOutSize, cOut, hashAlg, label, dInSize, dIn 854 #ifdef TEST_RSA
855 | ||
856 | #endif | |
857 | ||
858 | break; |
,NULL
);
859 | default: | |
860 | return CRYPT_SCHEME; | |
861 | } | |
862 | // All the schemes that do padding will come here for the encryption step | |
863 | // Check that the Encoding worked | |
864 | if(retVal != CRYPT_SUCCESS) | |
865 | return retVal; | |
866 | ||
867 | // Padding OK so do the encryption | |
868 | return RSAEP(*cOutSize, cOut, key); | |
869 | } |
This is the entry point for decryption using RSA. Decryption is use of the private exponent. The padType
parameter determines what padding was used.
Return Value | Meaning |
CRYPT_SUCCESS | successful completion |
CRYPT_PARAMETER | cInSize is not the same as the size of the public modulus of key; or numeric value of the encrypted data is greater than the modulus |
CRYPT_FAIL | dOutSize is not large enough for the result |
CRYPT_SCHEME | padType is not supported |
870 LIB_EXPORT CRYPT_RESULT
871 _cpri DecryptRSA(
872 UINT32 *dOutSize, // OUT: the size of the decrypted data 873 BYTE *dOut, // OUT: the decrypted data
874 RSA_KEY *key, // IN: the key to use for decryption 875 TPM_ALG_ID padType, // IN: the type of padding
876 UINT32 cInSize, // IN: the amount of data to decrypt 877 BYTE *cIn, // IN: the data to decrypt
878 TPM_ALG_ID hashAlg, // IN: in case this is needed for the scheme 879 const char *label // IN: in case it is needed for the scheme 880 )
881 {
882 CRYPT_RESULT retVal;
883
884 // Make sure that the necessary parameters are provided
885 pAssert(cIn != NULL && dOut != NULL && dOutSize != NULL && key != NULL); 886
887 // Size is checked to make sure that the decryption works properly 888 if(cInSize != key->publicKey->size)
889 return CRYPT_PARAMETER;
890
891 // For others that do padding, do the decryption in place and then 892 // go handle the decoding.
893 if((retVal = RSADP(cInSize, cIn, key)) != CRYPT_SUCCESS) 894 return retVal; // Decryption failed
895
896 // Remove padding
897 switch (padType)
898 {
899 case TPM_ALG_NULL:
900 if(*dOutSize < key->publicKey->size) 901 return CRYPT_FAIL;
902 *dOutSize = key->publicKey->size;
903 memcpy(dOut, cIn, *dOutSize);
904 return CRYPT_SUCCESS;
905 case TPM_ALG_RSAES:
906 return RSAES_Decode(dOutSize, dOut, cInSize, cIn);
907 | break; | |
908 | case TPM_ALG_OAEP: | |
909 | return OaepDecode(dOutSize, dOut, hashAlg, label, cInSize, cIn); | |
910 | break; | |
911 | default: | |
912 | return CRYPT_SCHEME; | |
913 | break; | |
914 | } | |
915 | } |
This function is used to generate an RSA signature of the type indicated in scheme.
Return Value | Meaning |
CRYPT_SUCCESS | sign operation completed normally |
CRYPT_SCHEME | scheme or hashAlg are not supported |
CRYPT_PARAMETER | hInSize does not match hashAlg (for RSASSA) |
916 LIB_EXPORT CRYPT_RESULT
917 _cpri SignRSA(
918 UINT32 *sigOutSize, // OUT: size of signature 919 BYTE *sigOut, // OUT: signature
920 RSA_KEY *key, // IN: key to use
921 TPM_ALG_ID scheme, // IN: the scheme to use
922 TPM_ALG_ID hashAlg, // IN: hash algorithm for PKSC1v1_5 923 UINT32 hInSize, // IN: size of digest to be signed 924 BYTE *hIn // IN: digest buffer
925 )
926 {
927 CRYPT_RESULT retVal;
928
929 // Parameter checks
930 pAssert(sigOutSize != NULL && sigOut != NULL && key != NULL && hIn != NULL); 931
932 // For all signatures the size is the size of the key modulus 933 *sigOutSize = key->publicKey->size;
934 switch (scheme)
935 {
case TPM_ALG_NULL:
*sigOutSize = 0;
return CRYPT_SUCCESS;
case TPM_ALG_RSAPSS:
// PssEncode can return CRYPT_PARAMETER
retVal = PssEncode(*sigOutSize, sigOut, hashAlg, hInSize, hIn 942 #ifdef TEST_RSA
943 , NULL
944 #endif
945 );
946 break;
947 case TPM_ALG_RSASSA:
948 // RSASSA_Encode can return CRYPT_PARAMETER or CRYPT_SCHEME
949 retVal = RSASSA_Encode(*sigOutSize, sigOut, hashAlg, hInSize, hIn); 950 break;
951 default:
952 return CRYPT_SCHEME;
953 }
954 if(retVal != CRYPT_SUCCESS)
955 return retVal;
956 // Do the encryption using the private key 957 // RSADP can return CRYPT_PARAMETR
958 return RSADP(*sigOutSize,sigOut, key);
959 }
_cpri__ValidateSignatureRSA()
This function is used to validate an RSA signature. If the signature is valid CRYPT_SUCCESS is returned. If the signature is not valid, CRYPT_FAIL is returned. Other return codes indicate either parameter problems or fatal errors.
Return Value | Meaning |
CRYPT_SUCCESS | the signature checks |
CRYPT_FAIL | the signature does not check |
CRYPT_SCHEME | unsupported scheme or hash algorithm |
960 LIB_EXPORT CRYPT_RESULT
961 _cpri ValidateSignatureRSA(
962 RSA_KEY *key, // IN: key to use
963 TPM_ALG_ID scheme, // IN: the scheme to use 964 TPM_ALG_ID hashAlg, // IN: hash algorithm
965 UINT32 hInSize, // IN: size of digest to be checked 966 BYTE *hIn, // IN: digest buffer
967 UINT32 sigInSize, // IN: size of signature 968 BYTE *sigIn, // IN: signature
969 UINT16 saltSize // IN: salt size for PSS 970 )
971 {
972 CRYPT_RESULT retVal;
973
974 // Fatal programming errors
975 pAssert(key != NULL && sigIn != NULL && hIn != NULL); 976
977 // Errors that might be caused by calling parameters 978 if(sigInSize != key->publicKey->size)
979 return CRYPT_FAIL; 980 // Decrypt the block
981 if((retVal = RSAEP(sigInSize, sigIn, key)) != CRYPT_SUCCESS) 982 return CRYPT_FAIL;
983 switch (scheme)
984 {
985 case TPM_ALG_NULL:
986 return CRYPT_SCHEME;
987 break;
988 case TPM_ALG_RSAPSS:
989 return PssDecode(hashAlg, hInSize, hIn, sigInSize, sigIn, saltSize); 990 break;
991 case TPM_ALG_RSASSA:
992 return RSASSA_Decode(hashAlg, hInSize, hIn, sigInSize, sigIn); 993 break;
994 default:
995 break;
996 }
997 return CRYPT_SCHEME;
998 }
999 #ifndef RSA_KEY_SIEVE
Generate an RSA key from a provided seed
Return Value | Meaning |
CRYPT_FAIL | exponent is not prime or is less than 3; or could not find a prime using the provided parameters |
CRYPT_CANCEL | operation was canceled |
1000 LIB_EXPORT CRYPT_RESULT
1001 _cpri GenerateKeyRSA(
1002 TPM2B *n, // OUT: The public modulu
1003 TPM2B *p, // OUT: One of the prime factors of n 1004 UINT16 keySizeInBits, // IN: Size of the public modulus in bit 1005 UINT32 e, // IN: The public exponent
1006 TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key 1007 // generation proce
1008 TPM2B *seed, // IN: the seed to use
1009 const char *label, // IN: A label for the generation process. 1010 TPM2B *extra, // IN: Party 1 data for the KDF
1011 UINT32 *counter // IN/OUT: Counter value to allow KFD iteration 1012 // to be propagated across multiple routine 1013 )
1014 {
1015 UINT32 lLen; // length of the label
1016 // (counting the terminating 0);
1017 UINT16 digestSize = _cpri GetDigestSize(hashAlg); 1018
1019 TPM2B_HASH_BLOCK oPadKey;
1020 | ||
1021 | UINT32 outer; | |
1022 | UINT32 inner; | |
1023 | BYTE swapped[4]; | |
1024 | ||
1025 | CRYPT_RESULT retVal; | |
1026 | int i, fill; | |
1027 | const static char defaultLabel[] = "RSA key"; | |
1028 | BYTE *pb; | |
1029 | ||
1030 | CPRI_HASH_STATE h1; // contains the hash of the | |
1031 | // HMAC key w/ iPad | |
1032 | CPRI_HASH_STATE h2; // contains the hash of the | |
1033 | // HMAC key w/ oPad | |
1034 | CPRI_HASH_STATE h; // the working hash context | |
1035 | ||
1036 | BIGNUM *bnP; | |
1037 | BIGNUM *bnQ; | |
1038 | BIGNUM *bnT; | |
1039 | BIGNUM *bnE; | |
1040 | BIGNUM *bnN; | |
1041 | BN_CTX *context; | |
1042 | UINT32 rem; | |
1043 | ||
1044 | // Make sure that hashAlg is valid hash | |
1045 | pAssert(digestSize != 0); | |
1046 | ||
1047 | // if present, use externally provided counter | |
1048 | if(counter != NULL) | |
1049 | outer = *counter; | |
1050 | else | |
1051 | outer = 1; | |
1052 | ||
1053 | // Validate exponent | |
1054 | UINT32_TO_BYTE_ARRAY(e, swapped); | |
1055 | ||
1056 | // Need to check that the exponent is prime and not less than | 3 |
1057 | if( e != 0 && (e < 3 || !_math IsPrime(e))) |
1058 return CRYPT_FAIL;
1059
1060 // Get structures for the big number representations 1061 context = BN_CTX_new();
1062 if(context == NULL)
1063 FAIL(FATAL_ERROR_ALLOCATION);
1064 BN_CTX_start(context); 1065 bnP = BN_CTX_get(context); 1066 bnQ = BN_CTX_get(context); 1067 bnT = BN_CTX_get(context); 1068 bnE = BN_CTX_get(context); 1069 bnN = BN_CTX_get(context); 1070 if(bnN == NULL)
1071 FAIL(FATAL_ERROR_INTERNAL);
1072
1073 // Set Q to zero. This is used as a flag. The prime is computed in P. When a 1074 // new prime is found, Q is checked to see if it is zero. If so, P is copied 1075 // to Q and a new P is found. When both P and Q are non-zero, the modulus and 1076 // private exponent are computed and a trial encryption/decryption is
1077 // performed. If the encrypt/decrypt fails, assume that at least one of the 1078 // primes is composite. Since we don't know which one, set Q to zero and start 1079 // over and find a new pair of primes.
1080 BN_zero(bnQ);
1081
1082 // Need to have some label 1083 if(label == NULL)
1084 label = (const char *)&defaultLabel; 1085 // Get the label size
1086 for(lLen = 0; label[lLen++] != 0;);
1087
1088 // Start the hash using the seed and get the intermediate hash value
1089 _cpri StartHMAC(hashAlg, FALSE, &h1, seed->size, seed->buffer, &oPadKey.b); 1090 _cpri StartHash(hashAlg, FALSE, &h2);
1091 _cpri UpdateHash(&h2, oPadKey.b.size, oPadKey.b.buffer); 1092
1093 n->size = (keySizeInBits +7)/8;
1094 pAssert(n->size <= MAX_RSA_KEY_BYTES); 1095 p->size = n->size / 2;
1096 if(e == 0)
1097 e = RSA_DEFAULT_PUBLIC_EXPONENT;
1098
1099 BN_set_word(bnE, e);
1100
1101 // The first test will increment the counter from zero. 1102 for(outer += 1; outer != 0; outer++)
1103 {
1104 if(_plat IsCanceled())
1105 {
1106 retVal = CRYPT_CANCEL;
1107 goto Cleanup;
1108 }
1109
1110 // Need to fill in the candidate with the hash 1111 fill = digestSize;
1112 pb = p->buffer; 1113
1114 // Reset the inner counter
1115 inner = 0;
1116 for(i = p->size; i > 0; i -= digestSize)
1117 {
1118 inner++;
1119 // Initialize the HMAC with saved state
1120 _cpri CopyHashState(&h, &h1);
1121
1122 // Hash the inner counter (the one that changes on each HMAC iteration) 1123 UINT32_TO_BYTE_ARRAY(inner, swapped);
1124 | _cpri UpdateHash(&h, 4, swapped); | |
1125 | _cpri UpdateHash(&h, lLen, (BYTE *)label); | |
1126 | ||
1127 | // Is there any party 1 data | |
1128 | if(extra != NULL) | |
1129 | _cpri UpdateHash(&h, extra->size, extra->buffer); | |
1130 | ||
1131 | // Include the outer counter (the one that changes on | each prime |
1132 | // prime candidate generation | |
1133 | UINT32_TO_BYTE_ARRAY(outer, swapped); | |
1134 | _cpri UpdateHash(&h, 4, swapped); | |
1135 | _cpri UpdateHash(&h, 2, (BYTE *)&keySizeInBits); | |
1136 | if(i < fill) | |
1137 | fill = i; | |
1138 | _cpri CompleteHash(&h, fill, pb); | |
1139 | ||
1140 | // Restart the oPad hash | |
1141 | _cpri CopyHashState(&h, &h2); | |
1142 | ||
1143 | // Add the last hashed data | |
1144 | _cpri UpdateHash(&h, fill, pb); | |
1145 | ||
1146 | // gives a completed HMAC | |
1147 | _cpri CompleteHash(&h, fill, pb); | |
1148 | pb += fill; | |
1149 | } | |
1150 | // Set the Most significant 2 bits and the low bit of the | candidate |
1151 | p->buffer[0] |= 0xC0; | |
1152 | p->buffer[p->size - 1] |= 1; | |
1153 | ||
1154 | // Convert the candidate to a BN | |
1155 | BN_bin2bn(p->buffer, p->size, bnP); | |
1156 | ||
1157 | // If this is the second prime, make sure that it differs | from the |
1158 | // first prime by at least 2^100 | |
1159 | if(!BN_is_zero(bnQ)) | |
1160 | { | |
1161 | // bnQ is non-zero if we already found it | |
1162 | if(BN_ucmp(bnP, bnQ) < 0) | |
1163 | BN_sub(bnT, bnQ, bnP); | |
1164 | else | |
1165 | BN_sub(bnT, bnP, bnQ); |
1166 if(BN_num_bits(bnT) < 100) // Difference has to be at least 100 bits 1167 continue;
1168 }
1169 // Make sure that the prime candidate (p) is not divisible by the exponent 1170 // and that (p-1) is not divisible by the exponent
1171 // Get the remainder after dividing by the modulus 1172 rem = BN_mod_word(bnP, e);
1173 if(rem == 0) // evenly divisible so add two keeping the number odd and 1174 // making sure that 1 != p mod e
1175 BN_add_word(bnP, 2);
1176 else if(rem == 1) // leaves a remainder of 1 so subtract two keeping the 1177 // number odd and making (e-1) = p mod e
1178 BN_sub_word(bnP, 2);
1179
1180 // Have a candidate, check for primality
1181 if((retVal = (CRYPT_RESULT)BN_is_prime_ex(bnP, 1182 BN_prime_checks, NULL, NULL)) < 0)
1183 FAIL(FATAL_ERROR_INTERNAL);
1184
1185 if(retVal != 1)
1186 continue;
1187
1188 // Found a prime, is this the first or second. 1189 if(BN_is_zero(bnQ))
1190 {
1191 // copy p to q and compute another prime in p
1192 BN_copy(bnQ, bnP);
1193 continue;
1194 }
1195 //Form the public modulus
1196 BN_mul(bnN, bnP, bnQ, context);
1197 if(BN_num_bits(bnN) != keySizeInBits) 1198 FAIL(FATAL_ERROR_INTERNAL);
1199
1200 // Save the public modulus
1201 BnTo2B(n, bnN, n->size); // Will pad the buffer to the correct size 1202 pAssert((n->buffer[0] & 0x80) != 0);
1203
1204 // And one prime
1205 BnTo2B(p, bnP, p->size);
1206 pAssert((p->buffer[0] & 0x80) != 0);
1207
1208 // Finish by making sure that we can form the modular inverse of PHI 1209 // with respect to the public exponent
1210 // Compute PHI = (p - 1)(q - 1) = n - p - q + 1 1211 // Make sure that we can form the modular inverse 1212 BN_sub(bnT, bnN, bnP);
1213 BN_sub(bnT, bnT, bnQ);
1214 BN_add_word(bnT, 1);
1215
1216 // find d such that (Phi * d) mod e ==1
1217 // If there isn't then we are broken because we took the step 1218 // of making sure that the prime != 1 mod e so the modular inverse 1219 // must exist
1220 if(BN_mod_inverse(bnT, bnE, bnT, context) == NULL || BN_is_zero(bnT)) 1221 FAIL(FATAL_ERROR_INTERNAL);
1222
1223 // And, finally, do a trial encryption decryption 1224 {
1225 TPM2B_TYPE(RSA_KEY, MAX_RSA_KEY_BYTES);
1226 TPM2B_RSA_KEY r;
1227 r.t.size = sizeof(n->size); 1228
1229 // If we are using a seed, then results must be reproducible on each 1230 // call. Otherwise, just get a random number
1231 if(seed == NULL)
1232 _cpri GenerateRandom(n->size, r.t.buffer);
1233 else
1234 {
1235 // this this version does not have a deterministic RNG, XOR the
1236 // public key and private exponent to get a deterministic value
1237 // for testing.
1238 int i;
1239
1240 // Generate a random-ish number starting with the public modulus
1241 // XORed with the MSO of the seed
1242 for(i = 0; i < n->size; i++)
1243 r.t.buffer[i] = n->buffer[i] ^ seed->buffer[0]; 1244 }
1245 // Make sure that the number is smaller than the public modulus 1246 r.t.buffer[0] &= 0x7F;
1247 // Convert
1248 if( BN_bin2bn(r.t.buffer, r.t.size, bnP) == NULL 1249 // Encrypt with the public exponent
1250 || BN_mod_exp(bnQ, bnP, bnE, bnN, context) != 1 1251 // Decrypt with the private exponent
1252 || BN_mod_exp(bnQ, bnQ, bnT, bnN, context) != 1)
1253 FAIL(FATAL_ERROR_INTERNAL);
1254 // If the starting and ending values are not the same, start over )-; 1255 if(BN_ucmp(bnP, bnQ) != 0)
1256 {
1257 BN_zero(bnQ);
1258 continue;
1259 }
1260 }
1261 retVal = CRYPT_SUCCESS;
1262 goto Cleanup;
1263 }
1264 retVal = CRYPT_FAIL;
1265
1266 Cleanup:
1267 // Close out the hash sessions 1268 _cpri CompleteHash(&h2, 0, NULL);
1269 _cpri CompleteHash(&h1, 0, NULL);
1270
1271 // Free up allocated BN values 1272 BN_CTX_end(context);
1273 BN_CTX_free(context);
1274 if(counter != NULL) 1275 *counter = outer; 1276 return retVal;
1277 }
1278 #endif // RSA_KEY_SIEVE
1279 #endif // TPM_ALG_RSA
Alternative RSA Key Generation
The files in this clause implement an alternative RSA key generation method that is about an order of magnitude faster than the regular method in B.14.1 and is provided simply to speed testing of the test functions. The method implemented in this clause uses a sieve rather than choosing prime candidates at random and testing for primeness. In this alternative, the sieve filed starting address is chosen at random and a sieve operation is performed on the field using small prime values. After sieving, the bits representing values that are not divisible by the small primes tested, will be checked in a pseudo-random order until a prime is found.
The size of the sieve field is tunable as is the value indicating the number of primes that should be checked. As the size of the prime increases, the density of primes is reduced so the size of the sieve field should be increased to improve the probability that the field will contain at least one prime. In addition, as the sieve field increases the number of small primes that should be checked increases. Eliminating a number from consideration by using division is considerably faster than eliminating the number with a Miller-Rabin test.
This header file is used to for parameterization of the Sieve and RNG used by the RSA module
1 | #ifndef | RSA_H |
2 | #define | RSA_H |
This value is used to set the size of the table that is searched by the prime iterator. This is used during the generation of different primes. The smaller tables are used when generating smaller primes.
3 extern const UINT16 primeTableBytes;
The following define determines how large the prime number difference table will be defined. The value of 13 will allocate the maximum size table which allows generation of the first 6542 primes which is all the primes less than 2^16.
#define PRIME_DIFF_TABLE_512_BYTE_PAGES 13
This set of macros used the value above to set the table size.
#ifndef PRIME_DIFF_TABLE_512_BYTE_PAGES
# define PRIME_DIFF_TABLE_512_BYTE_PAGES 4
#endif
#ifdef PRIME_DIFF_TABLE_512_BYTE_PAGES
# if PRIME_DIFF_TABLE_512_BYTE_PAGES > 12
# define PRIME_DIFF_TABLE_BYTES 6542
# else
# if PRIME_DIFF_TABLE_512_BYTE_PAGES <= 0
# define PRIME_DIFF_TABLE_BYTES 512
# else
# define PRIME_DIFF_TABLE_BYTES (PRIME_DIFF_TABLE_512_BYTE_PAGES * 512)
# endif
# endif
#endif
extern const BYTE primeDiffTable [PRIME_DIFF_TABLE_BYTES];
This determines the number of bits in the sieve field This must be a power of two.
#define FIELD_POWER 14 // This is the only value in this group that should be
// changed
#define FIELD_BITS (1 << FIELD_POWER)
#define MAX_FIELD_SIZE ((FIELD_BITS / 8) + 1)
This is the pre-sieved table. It already has the bits for multiples of 3, 5, and 7 cleared.
24 | #define SEED_VALUES_SIZE | 105 |
25 | const extern BYTE | seedValues[SEED_VALUES_SIZE]; |
This allows determination of the number of bits that are set in a byte without having to count them individually.
const extern BYTE bitsInByte[256];
This is the iterator structure for accessing the compressed prime number table. The expectation is that values will need to be accesses sequentially. This tries to save some data access.
typedef struct {
UINT32 lastPrime;
UINT32 index;
UINT32 final;
} PRIME_ITERATOR;
#ifdef RSA_INSTRUMENT
# define INSTRUMENT_SET(a, b) ((a) = (b))
# define INSTRUMENT_ADD(a, b) (a) = (a) + (b)
# define INSTRUMENT_INC(a) (a) = (a) + 1
extern UINT32 failedAtIteration[10];
extern UINT32 MillerRabinTrials;
extern UINT32 totalFieldsSieved;
extern UINT32 emptyFieldsSieved;
extern UINT32 noPrimeFields;
extern UINT32 primesChecked;
extern UINT16 lastSievePrime;
#else
# define INSTRUMENT_SET(a, b)
# define INSTRUMENT_ADD(a, b)
# define INSTRUMENT_INC(a)
#endif
#ifdef RSA_DEBUG
extern UINT16 defaultFieldSize;
50 | #define NUM_PRIMES | 2047 |
51 | extern const int16 | primes[NUM_PRIMES]; |
52 | #else | |
53 | #define defaultFieldSize | MAX_FIELD_SIZE |
54 | #endif | |
55 | #endif |
#include "OsslCryptoEngine.h"
#ifdef TPM_ALG_RSA
This file produces no code unless the compile switch is set to cause it to generate code.
3 | #ifdef | RSA_KEY_SIEVE |
4 | #include | "RsaKeySieve.h" |
//%
This next line will show up in the header file for this code. It will make the local functions public when debugging.
//%#ifdef RSA_DEBUG
Bit Manipulation Functions B.12.2.3.2.1. Introduction
These functions operate on a bit array. A bit array is an array of bytes with the 0th byte being the byte with the lowest memory address. Within the byte, bit 0 is the least significant bit.
This function will CLEAR a bit in a bit array.
void
ClearBit(
unsigned char *a, // IN: A pointer to an array of byte
int i // IN: the number of the bit to CLEAR 10 )
11 {
12 a[i >> 3] &= 0xff ^ (1 << (i & 7));
13 }
Function to SET a bit in a bit array.
void
SetBit(
unsigned char *a, // IN: A pointer to an array of byte
int i // IN: the number of the bit to SET 18 )
19 {
20 a[i >> 3] |= (1 << (i & 7));
21 }
Function to test if a bit in a bit array is SET.
Return Value | Meaning |
0 | bit is CLEAR |
1 | bit is SET |
UINT32
IsBitSet(
unsigned char *a, // IN: A pointer to an array of byte
int i // IN: the number of the bit to test 26 )
27 {
28 return ((a[i >> 3] & (1 << (i & 7))) != 0);
29 }
This function counts the number of bits set in an array of bytes.
int
BitsInArray(
unsigned char *a, // IN: A pointer to an array of byte
int i // IN: the number of bytes to sum 34 )
35 {
36 int j = 0;
37 for(; i ; i--)
j += bitsInByte[*a++];
return j; 40 }
This function finds the nth SET bit in a bit array. The caller should check that the offset of the returned value is not out of range. If called when the array does not have n bits set, it will return a fatal error
UINT32
FindNthSetBit(
const UINT16 aSize, // IN: the size of the array to check
const BYTE *a, // IN: the array to check
const UINT32 n // IN, the number of the SET bit 46 )
47 {
UINT32 i;
const BYTE *pA = a;
UINT32 retValue;
BYTE sel; 52
53 (aSize); 54
//find the bit
for(i = 0; i < n; i += bitsInByte[*pA++]); 57
// The chosen bit is in the byte that was just accessed
// Compute the offset to the start of that byte 60 pA--;
61 retValue = (UINT32)(pA - a) * 8; 62
// Subtract the bits in the last byte added.
i -= bitsInByte[*pA]; 65
66 // Now process the byte, one bit at a time.
67 for(sel = *pA; sel != 0 ; sel = sel >> 1) 68 {
69 if(sel & 1)
70 {
71 i += 1;
if(i == n)
return retValue;
74 }
75 retValue += 1; 76 }
77 FAIL(FATAL_ERROR_INTERNAL); 78 }
Miscellaneous Functions B.12.2.3.3.1. RandomForRsa()
This function uses a special form of KDFa() to produces a pseudo random sequence. It's input is a structure that contains pointers to a pre-computed set of hash contexts that are set up for the HMAC computations using the seed.
This function will test that ktx.outer will not wrap to zero if incremented. If so, the function returns FALSE. Otherwise, the ktx.outer is incremented before each number is generated.
void
RandomForRsa(
KDFa_CONTEXT *ktx, // IN: a context for the KDF
const char *label, // IN: a use qualifying label
TPM2B *p // OUT: the pseudo random result 84 )
85 {
INT16 i;
UINT32 inner;
BYTE swapped[4];
UINT16 fill;
BYTE *pb;
UINT16 lLen = 0;
UINT16 digestSize = _cpri GetDigestSize(ktx->hashAlg);
CPRI_HASH_STATE h; // the working hash context 94
if(label != NULL)
for(lLen = 0; label[lLen++];);
fill = digestSize;
pb = p->buffer;
inner = 0;
100 *(ktx->outer) += 1;
101 for(i = p->size; i > 0; i -= digestSize)
102 {
103 inner++;
104
// Initialize the HMAC with saved state
_cpri CopyHashState(&h, &(ktx->iPadCtx)); 107
// Hash the inner counter (the one that changes on each HMAC iteration)
UINT32_TO_BYTE_ARRAY(inner, swapped);
_cpri UpdateHash(&h, 4, swapped);
if(lLen != 0)
_cpri UpdateHash(&h, lLen, (BYTE *)label); 113
// Is there any party 1 data
if(ktx->extra != NULL)
_cpri UpdateHash(&h, ktx->extra->size, ktx->extra->buffer);
118 | // Include the outer counter (the one that changes on each | prime | |
119 | // prime candidate generation | ||
120 | UINT32_TO_BYTE_ARRAY(*(ktx->outer), swapped); | ||
121 | _cpri UpdateHash(&h, 4, swapped); | ||
122 | _cpri UpdateHash(&h, 2, (BYTE *)&ktx->keySizeInBits); | ||
123 | if(i < fill) | ||
124 | fill = i; | ||
125 | _cpri CompleteHash(&h, fill, pb); | ||
126 | |||
127 | // Restart the oPad hash | ||
128 | _cpri CopyHashState(&h, &(ktx->oPadCtx)); | ||
129 | |||
130 | // Add the last hashed data | ||
131 | _cpri UpdateHash(&h, fill, pb); | ||
132 | |||
133 | // gives a completed HMAC | ||
134 | _cpri CompleteHash(&h, fill, pb); | ||
135 | pb += fill; | ||
136 | } | ||
137 | return; | ||
138 | } |
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.
UINT32
MillerRabinRounds(
UINT32 bits // IN: Number of bits in the RSA prime
142 )
143 {
if(bits < 511) return 8; // don't really expect this
if(bits < 1536) return 5; // for 512 and 1K primes
return 4; // for 3K public modulus and greater
147 }
This function performs a Miller-Rabin test from FIPS 186-3. It does iterations trials on the number. I all likelihood, if the number is not prime, the first test fails.
If a KDFa(), PRNG context is provide (ktx), then it is used to provide the random values. Otherwise, the random numbers are retrieved from the random number generator.
Return Value | Meaning |
TRUE | probably prime |
FALSE | composite |
148 | BOOL | |
149 | MillerRabin( | |
150 | BIGNUM | *bnW, |
151 | int | iterations, |
152 | KDFa_CONTEXT | *ktx, |
153 | BN_CTX | *context |
154 | ) | |
155 | { | |
156 | BIGNUM | *bnWm1; |
157 | BIGNUM | *bnM; |
158 | BIGNUM | *bnB; |
159 | BIGNUM | *bnZ; |
BOOL ret = FALSE; // Assumed composite for easy exit
TPM2B_TYPE(MAX_PRIME, MAX_RSA_KEY_BYTES/2);
TPM2B_MAX_PRIME b;
int a;
int j;
int wLen;
int i; 167
pAssert(BN_is_bit_set(bnW, 0));
INSTRUMENT_INC(MillerRabinTrials); // Instrumentation 170
BN_CTX_start(context);
bnWm1 = BN_CTX_get(context);
bnB = BN_CTX_get(context);
bnZ = BN_CTX_get(context);
bnM = BN_CTX_get(context);
if(bnM == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 178
// Let a be the largest integer such that 2^a divides w1.
BN_copy(bnWm1, bnW);
BN_sub_word(bnWm1, 1);
// Since w is odd (w-1) is even so start at bit number 1 rather than 0
for(a = 1; !BN_is_bit_set(bnWm1, a); a++); 184
185 // 2. m = (w1) / 2^a
186 BN_rshift(bnM, bnWm1, a); 187
// 3. wlen = len (w).
wLen = BN_num_bits(bnW);
pAssert((wLen & 7) == 0); 191
// Set the size for the random number
b.b.size = (UINT16)(wLen + 7)/8; 194
// 4. For i = 1 to iterations do
for(i = 0; i < iterations ; i++)
197 {
198
// 4.1 Obtain a string b of wlen bits from an RBG.
step4point1:
// In the reference implementation, wLen is always a multiple of 8
if(ktx != NULL)
RandomForRsa(ktx, "Miller-Rabin witness", &b.b);
else
_cpri GenerateRandom(b.t.size, b.t.buffer); 206
if(BN_bin2bn(b.t.buffer, b.t.size, bnB) == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 209
// 4.2 If ((b 1) or (b w1)), then go to step 4.1.
if(BN_is_zero(bnB))
goto step4point1;
if(BN_is_one(bnB))
goto step4point1;
if(BN_ucmp(bnB, bnWm1) >= 0)
goto step4point1; 217
218 // 4.3 z = b^m mod w.
if(BN_mod_exp(bnZ, bnB, bnM, bnW, context) != 1)
FAIL(FATAL_ERROR_ALLOCATION); 221
222 // 4.4 If ((z = 1) or (z = w 1)), then go to step 4.7.
if(BN_is_one(bnZ) || BN_ucmp(bnZ, bnWm1) == 0)
goto step4point7;
226 | // 4.5 For j = 1 to a 1 do. | |
227 | for(j = 1; j < a; j++) | |
228 | { | |
229 | // 4.5.1 z = z^2 mod w. | |
230 | if(BN_mod_mul(bnZ, bnZ, bnZ, bnW, context) != 1) | |
231 | FAIL(FATAL_ERROR_ALLOCATION); | |
232 | ||
233 | // 4.5.2 If (z = w1), then go to step 4.7. | |
234 | if(BN_ucmp(bnZ, bnWm1) == 0) | |
235 | goto step4point7; | |
236 | ||
237 | // 4.5.3 If (z = 1), then go to step 4.6. | |
238 | if(BN_is_one(bnZ)) | |
239 | goto step4point6; | |
240 | } | |
241 | // 4.6 Return COMPOSITE. | |
242 | step4point6: | |
243 | if(i > 9) | |
244 | INSTRUMENT_INC(failedAtIteration[9]); | |
245 | else | |
246 | INSTRUMENT_INC(failedAtIteration[i]); | |
247 | goto end; | |
248 | ||
249 | // 4.7 Continue. Comment: Increment i for the do-loop in step | 4. |
250 | step4point7: | |
251 | continue; | |
252 | } | |
253 | // 5. Return PROBABLY PRIME | |
254 | ret = TRUE; | |
255 | ||
256 | end: | |
257 | BN_CTX_end(context); | |
258 | return ret; | |
259 | } | |
This function is used to access the next prime number in the sequence | of primes. It requires a pre- | |
initialized iterator. | ||
260 | UINT32 | |
261 | NextPrime( | |
262 | PRIME_ITERATOR *iter | |
263 | ) | |
264 | { | |
265 | if(iter->index >= iter->final) | |
266 | return (iter->lastPrime = 0); |
267 return (iter->lastPrime += primeDiffTable[iter->index++]);
268 }
Modifies the input parameter to be a valid value for the number of primes. The adjusted value is either the input value rounded up to the next 512 bytes boundary or the maximum value of the implementation. If the input is 0, the return is set to the maximum.
UINT32
AdjustNumberOfPrimes(
UINT32 p
272 )
273 {
274 p = ((p + 511) / 512) * 512;
if(p == 0 || p > PRIME_DIFF_TABLE_BYTES)
p = PRIME_DIFF_TABLE_BYTES;
return p;
278 }
This function is used to initialize the prime sequence generator iterator. The iterator is initialized and returns the first prime that is equal to the requested starting value. If the starting value is no a prime, then the iterator is initialized to the next higher prime number.
UINT32
PrimeInit(
UINT32 first, // IN: the initial prime
PRIME_ITERATOR *iter, // IN/OUT: the iterator structure
UINT32 primes // IN: the table length
284 )
285 { 286
iter->lastPrime = 1;
iter->index = 0;
iter->final = AdjustNumberOfPrimes(primes);
while(iter->lastPrime < first)
NextPrime(iter);
return iter->lastPrime;
293 }
This macro sets the default number of primes to the indicated value.
//%#define SetDefaultNumberOfPrimes(p) (primeTableBytes = AdjustNumberOfPrimes(p))
Checks to see if a UINT32 is prime
Return Value | Meaning |
TRUE | number is prime |
FAIL | number is not prime |
BOOL
IsPrimeWord(
UINT32 p // IN: number to test
298 )
299 {
300 #if defined RSA_KEY_SIEVE && (PRIME_DIFF_TABLE_BYTES >= 6542) 301
UINT32 test;
UINT32 index;
UINT32 stop; 305
306 if((p & 1) == 0)
307 return FALSE; 308 if(p == 1 || p == 3)
309 return TRUE; 310
// Get a high value for the stopping point
for(index = p, stop = 0; index; index >>= 2)
313 stop = (stop << 1) + 1;
314 stop++; 315
316 // If the full prime difference value table is present, can check here 317
test = 3;
for(index = 1; index < PRIME_DIFF_TABLE_BYTES; index += 1)
320 {
321 if((p % test) == 0)
return (p == test);
if(test > stop)
return TRUE;
test += primeDiffTable[index];
326 }
327 return TRUE; 328
329 #else 330
BYTE b[4];
if(p == RSA_DEFAULT_PUBLIC_EXPONENT || p == 1 || p == 3 )
return TRUE;
334 if((p & 1) == 0)
return FALSE;
UINT32_TO_BYTE_ARRAY(p,b);
return _math IsPrime(p);
#endif
339 }
typedef struct {
UINT16 prime;
UINT16 count;
} SIEVE_MARKS;
const SIEVE_MARKS sieveMarks[5] = {
345 {31, 7}, {73, 5}, {241, 4}, {1621, 3}, {UINT16_MAX, 2}};
This function does a prime sieve over the input field which has as its starting address the value in bnN. Since this initializes the Sieve using a pre-computed field with the bits associated with 3, 5 and 7 already turned off, the value of pnN may need to be adjusted by a few counts to allow the pre-computed field to be used without modification. The fieldSize parameter must be 2^N + 1 and is probably not useful if it is less than 129 bytes (1024 bits).
UINT32
PrimeSieve(
BIGNUM *bnN, // IN/OUT: number to sieve
UINT32 fieldSize, // IN: size of the field area in bytes
BYTE *field, // IN: field
UINT32 primes // IN: the number of primes to use
352 )
353 {
UINT32 i;
UINT32 j;
UINT32 fieldBits = fieldSize * 8;
UINT32 r;
const BYTE *p1;
BYTE *p2;
PRIME_ITERATOR iter;
UINT32 adjust;
UINT32 mark = 0;
UINT32 count = sieveMarks[0].count;
UINT32 stop = sieveMarks[0].prime;
UINT32 composite; 366
367 // UINT64 test; //DEBUG
368 | ||
369 | pAssert(field != NULL && bnN != NULL); | |
370 | // Need to have a field that has a size of 2^n + 1 bytes | |
371 | pAssert(BitsInArray((BYTE *)&fieldSize, 2) == 2); | |
372 | ||
373 | primes = AdjustNumberOfPrimes(primes); | |
374 | ||
375 | // If the remainder is odd, then subtracting the value | |
376 | // will give an even number, but we want an odd number, | |
377 | // so subtract the 105+rem. Otherwise, just subtract | |
378 | // the even remainder. | |
379 | adjust = BN_mod_word(bnN,105); | |
380 | if(adjust & 1) | |
381 | adjust += 105; | |
382 | ||
383 | // seed the field | |
384 | // This starts the pointer at the nearest byte to the input value | |
385 | p1 = &seedValues[adjust/16]; | |
386 | ||
387 | // Reduce the number of bytes to transfer by the amount skipped | |
388 | j = sizeof(seedValues) - adjust/16; | |
389 | adjust = adjust % 16; | |
390 | BN_sub_word(bnN, adjust); | |
391 | adjust >>= 1; | |
392 | ||
393 | // This offsets the field | |
394 | p2 = field; | |
395 | for(i = fieldSize; i > 0; i--) | |
396 | { | |
397 | *p2++ = *p1++; | |
398 | if(--j == 0) | |
399 | { | |
400 | j = sizeof(seedValues); | |
401 | p1 = seedValues; | |
402 | } | |
403 | } | |
404 | // Mask the first bits in the field and the last byte in order to | eliminate |
405 | // bytes not in the field from consideration. | |
406 | field[0] &= 0xff << adjust; | |
407 | field[fieldSize-1] &= 0xff >> (8 - adjust); | |
408 | ||
409 | // Cycle through the primes, clearing bits | |
410 | // Have already done 3, 5, and 7 | |
411 | PrimeInit(7, &iter, primes); | |
412 | ||
413 | // Get the next N primes where N is determined by the mark in the | sieveMarks |
414 | while((composite = NextPrime(&iter)) != 0) | |
415 | { | |
416 | UINT32 pList[8]; | |
417 | UINT32 next = 0; | |
418 | i = count; | |
419 | pList[i--] = composite; | |
420 | for(; i > 0; i--) | |
421 | { | |
422 | next = NextPrime(&iter); | |
423 | pList[i] = next; | |
424 | if(next != 0) | |
425 | composite *= next; | |
426 | } | |
427 | composite = BN_mod_word(bnN, composite); | |
428 | for(i = count; i > 0; i--) | |
429 | { | |
430 | next = pList[i]; | |
431 | if(next == 0) | |
432 | goto done; | |
433 | r = composite % next; |
434 | if(r & 1) j = (next - r)/2; |
435 | else if(r == 0) j = 0; |
436 | else j = next - r/2; |
437 | for(; j < fieldBits; j += next) |
438 | ClearBit(field, j); |
439 | } |
440 | if(next >= stop) |
441 | { |
442 | mark++; |
443 | count = sieveMarks[mark].count; |
444 | stop = sieveMarks[mark].prime; |
445 | } |
446 | } |
447 | done: |
448 | INSTRUMENT_INC(totalFieldsSieved); |
449 | i = BitsInArray(field, fieldSize); |
450 | if(i == 0) INSTRUMENT_INC(emptyFieldsSieved); |
451 | return i; |
452 | } |
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. | |
453 | BOOL |
454 | PrimeSelectWithSieve( |
455 | BIGNUM *bnP, // IN/OUT: The candidate to filter |
456 | KDFa_CONTEXT *ktx, // IN: KDFa iterator structure |
457 | UINT32 e, // IN: the exponent |
458 | BN_CTX *context // IN: the big number context to play in |
459 | #ifdef RSA_DEBUG //% |
460 | ,UINT16 fieldSize, // IN: number of bytes in the field, as |
461 | // determined by the caller |
462 | UINT16 primes // IN: number of primes to use. |
463 | #endif //% |
464 | ) |
465 | { |
466 | BYTE field[MAX_FIELD_SIZE]; |
467 | UINT32 first; |
468 | UINT32 ones; |
469 | INT32 chosen; |
470 | UINT32 rounds = MillerRabinRounds(BN_num_bits(bnP)); |
471 | #ifndef RSA_DEBUG |
472 | UINT32 primes; |
473 | UINT32 fieldSize; |
474 | // Adjust the field size and prime table list to fit the size of the prime |
475 | // being tested. |
476 | primes = BN_num_bits(bnP); |
477 | if(primes <= 512) |
478 | { |
479 | primes = AdjustNumberOfPrimes(2048); |
480 | fieldSize = 65; |
481 | } |
482 | else if(primes <= 1024) |
483 | { |
484 | primes = AdjustNumberOfPrimes(4096); |
485 | fieldSize = 129; |
486 | } |
487 else
488 {
489 primes = AdjustNumberOfPrimes(0); // Set to the maximum
490 fieldSize = MAX_FIELD_SIZE;
491 }
492 if(fieldSize > MAX_FIELD_SIZE)
493 fieldSize = MAX_FIELD_SIZE;
494 #endif 495
496 // Save the low-order word to use as a search generator and make sure that
497 // it has some interesting range to it 498 first = bnP->d[0] | 0x80000000;
499
500 // Align to field boundary
501 bnP->d[0] &= ~((UINT32)(fieldSize-3));
502 pAssert(BN_is_bit_set(bnP, 0));
503 bnP->d[0] &= (UINT32_MAX << (FIELD_POWER + 1)) + 1;
504 ones = PrimeSieve(bnP, fieldSize, field, primes);
505 #ifdef RSA_FILTER_DEBUG
506 pAssert(ones == BitsInArray(field, defaultFieldSize));
507 #endif
508 for(; ones > 0; ones--)
509 {
#ifdef RSA_FILTER_DEBUG
if(ones != BitsInArray(field, defaultFieldSize))
FAIL(FATAL_ERROR_INTERNAL);
#endif
// Decide which bit to look at and find its offset
if(ones == 1)
ones = ones;
chosen = FindNthSetBit(defaultFieldSize, field,((first % ones) + 1));
if(chosen >= ((defaultFieldSize) * 8))
FAIL(FATAL_ERROR_INTERNAL); 520
521 // Set this as the trial prime
522 BN_add_word(bnP, chosen * 2); 523
524 // Use MR to see if this is prime
525 if(MillerRabin(bnP, rounds, ktx, context))
526 {
527 // Final check is to make sure that 0 != (p-1) mod e
528 // This is the same as -1 != p mod e ; or
529 // (e - 1) != p mod e
530 if((e <= 3) || (BN_mod_word(bnP, e) != (e-1)))
531 return TRUE;
532 }
533 // Back out the bit number
534 BN_sub_word(bnP, chosen * 2); 535
536 // Clear the bit just tested
537 ClearBit(field, chosen);
538 }
539 // Ran out of bits and couldn't find a prime in this field
540 INSTRUMENT_INC(noPrimeFields);
541 return FALSE;
542 }
B.12.2.3.3.11. AdjustPrimeCandiate()
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 is approximated with 0xB505 which is, in fixed point is 0.7071075439453125 or an error of 0.0001%. 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.
The function also puts the number on a field boundary.
543 void
544 AdjustPrimeCandidate(
545 BYTE *a,
546 | UINT16 len | ||
547 | ) | ||
548 | { | ||
549 | UINT16 highBytes; | ||
550 | |||
551 | highBytes = BYTE_ARRAY_TO_UINT16(a); | ||
552 | // This is fixed point arithmetic on 16-bit values | ||
553 | highBytes = ((UINT32)highBytes * (UINT32)0x4AFB) >> 16; | ||
554 | highBytes += 0xB505; | ||
555 | UINT16_TO_BYTE_ARRAY(highBytes, a); | ||
556 | a[len-1] |= 1; | ||
557 | } | ||
558 | void | ||
559 | GenerateRandomPrime( | ||
560 | TPM2B *p, | ||
561 | BN_CTX *ctx | ||
562 | #ifdef RSA_DEBUG //% | ||
563 | ,UINT16 field, | ||
564 | UINT16 primes | ||
565 | #endif //% | ||
566 | ) | ||
567 | { | ||
568 | BIGNUM *bnP; | ||
569 | BN_CTX *context; | ||
570 | |||
571 | if(ctx == NULL) context = BN_CTX_new(); | ||
572 | else context = ctx; | ||
573 | if(context == NULL) | ||
574 | FAIL(FATAL_ERROR_ALLOCATION); | ||
575 | BN_CTX_start(context); | ||
576 | bnP = BN_CTX_get(context); | ||
577 | |||
578 | while(TRUE) | ||
579 | { | ||
580 | _cpri GenerateRandom(p->size, p->buffer); | ||
581 | p->buffer[p->size-1] |= 1; | ||
582 | p->buffer[0] |= 0x80; | ||
583 | BN_bin2bn(p->buffer, p->size, bnP); | ||
584 | #ifdef RSA_DEBUG | ||
585 | if(PrimeSelectWithSieve(bnP, NULL, 0, context, field, | primes)) | |
586 | #else | ||
587 | if(PrimeSelectWithSieve(bnP, NULL, 0, context)) | ||
588 | #endif | ||
589 | break; | ||
590 | } | ||
591 | BnTo2B(p, bnP, (UINT16)BN_num_bytes(bnP)); | ||
592 | BN_CTX_end(context); | ||
593 | if(ctx == NULL) | ||
594 | BN_CTX_free(context); | ||
595 | return; | ||
596 | } | ||
597 | KDFa_CONTEXT * | ||
598 | KDFaContextStart( |
599 | KDFa_CONTEXT | *ktx, | // | IN/OUT: | the context structure to initialize |
600 | TPM2B | *seed, | // | IN: the | seed for the digest proce |
601 | TPM_ALG_ID | hashAlg, | // | IN: the | hash algorithm |
602 | TPM2B | *extra, | // | IN: the | extra data |
603 | UINT32 | *outer, | // | IN: the | outer iteration counter |
604 UINT16 keySizeInBit
605 )
606 {
607 UINT16 digestSize = _cpri GetDigestSize(hashAlg); 608 TPM2B_HASH_BLOCK oPadKey;
609
610 if(seed == NULL)
611 return NULL;
612
613 pAssert(ktx != NULL && outer != NULL && digestSize != 0); 614
615 // Start the hash using the seed and get the intermediate hash value
616 _cpri StartHMAC(hashAlg, FALSE, &(ktx->iPadCtx), seed->size, seed->buffer, 617 &oPadKey.b);
618 _cpri StartHash(hashAlg, FALSE, &(ktx->oPadCtx));
619 _cpri UpdateHash(&(ktx->oPadCtx), oPadKey.b.size, oPadKey.b.buffer); 620 ktx->extra = extra;
621 ktx->hashAlg = hashAlg; 622 ktx->outer = outer;
623 ktx->keySizeInBits = keySizeInBits; 624 return ktx;
625 }
626 void
627 KDFaContextEnd(
628 KDFa_CONTEXT *ktx // IN/OUT: the context structure to close 629 )
630 {
631 if(ktx != NULL)
632 {
633 // Close out the hash sessions
634 _cpri CompleteHash(&(ktx->iPadCtx), 0, NULL);
635 _cpri CompleteHash(&(ktx->oPadCtx), 0, NULL);
636 }
637 }
638 //%#endif
B.12.2.3.4. Public Function B.12.2.3.4.1. Introduction
This is the external entry for this replacement function. All this file provides is the substitute function to generate an RSA key. If the compiler settings are set appropriately, this this function will be used instead of the similarly named function in CpriRSA.c.
B.12.2.3.4.2. _cpri__GenerateKeyRSA()
Generate an RSA key from a provided seed
Return Value | Meaning |
CRYPT_FAIL | exponent is not prime or is less than 3; or could not find a prime using the provided parameters |
CRYPT_CANCEL | operation was canceled |
639 LIB_EXPORT CRYPT_RESULT
640 _cpri GenerateKeyRSA(
641 | TPM2B | *n, // OUT: The public modulus |
642 | TPM2B | *p, // OUT: One of the prime factors of n |
643 | UINT16 | keySizeInBits, // IN: Size of the public modulus in bits |
644 | UINT32 | e, // IN: The public exponent |
645 | TPM_ALG_ID | hashAlg, // IN: hash algorithm to use in the key |
646 | // generation process | |
647 | TPM2B | *seed, // IN: the seed to use |
648 | const char | *label, // IN: A label for the generation process. |
649 | TPM2B | *extra, // IN: Party 1 data for the KDF |
650 | UINT32 | *counter // IN/OUT: Counter value to allow KDF |
651 | // iteration to be propagated across | |
652 | // multiple routines | |
653 | #ifdef RSA_DEBUG | //% |
654 | ,UINT16 | primes, // IN: number of primes to test |
655 | UINT16 | fieldSize // IN: the field size to use |
656 | #endif | //% |
657 | ) | |
658 | { | |
659 | CRYPT_RESULT | retVal; |
660 | UINT32 | myCounter = 0; |
661 | UINT32 | *pCtr = (counter == NULL) ? &myCounter : counter; |
662 | ||
663 | KDFa_CONTEXT | ktx; |
664 | KDFa_CONTEXT | *ktxPtr; |
665 | UINT32 | i; |
666 | BIGNUM | *bnP; |
667 | BIGNUM | *bnQ; |
668 | BIGNUM | *bnT; |
669 | BIGNUM | *bnE; |
670 | BIGNUM | *bnN; |
671 | BN_CTX | *context; |
672 | ||
673 | // Make sure | that the required pointers are provided |
674 | pAssert(n != | NULL && p != NULL); |
675 |
676 // If the seed is provided, then use KDFa for generation of the 'random' 677 // values
678 ktxPtr = KDFaContextStart(&ktx, seed, hashAlg, extra, pCtr, keySizeInBits); 679
680 n->size = keySizeInBits/8;
681 p->size = n->size / 2;
682
// Validate exponent
if(e == 0 || e == RSA_DEFAULT_PUBLIC_EXPONENT)
e = RSA_DEFAULT_PUBLIC_EXPONENT;
else
if(!IsPrimeWord(e))
return CRYPT_FAIL;
689
690 // Get structures for the big number representations 691 context = BN_CTX_new();
BN_CTX_start(context);
bnP = BN_CTX_get(context);
bnQ = BN_CTX_get(context);
bnT = BN_CTX_get(context);
bnE = BN_CTX_get(context);
bnN = BN_CTX_get(context);
if(bnN == NULL)
FAIL(FATAL_ERROR_INTERNAL);
700
701 // Set Q to zero. This is used as a flag. The prime is computed in P. When a 702 // new prime is found, Q is checked to see if it is zero. If so, P is copied 703 // to Q and a new P is found. When both P and Q are non-zero, the modulus and 704 // private exponent are computed and a trial encryption/decryption is
705 // performed. If the encrypt/decrypt fails, assume that at least one of the 706 // primes is composite. Since we don't know which one, set Q to zero and start
707 // over and find a new pair of primes. 708 BN_zero(bnQ);
709 BN_set_word(bnE, e);
710
711 // Each call to generate a random value will increment ktx.outer 712 // it doesn't matter if ktx.outer wraps. This lets the caller 713 // use the initial value of the counter for additional entropy. 714 for(i = 0; i < UINT32_MAX; i++)
715 {
716 if(_plat IsCanceled())
717 {
718 retVal = CRYPT_CANCEL;
719 goto end;
720 }
// Get a random prime candidate.
if(seed == NULL)
_cpri GenerateRandom(p->size, p->buffer);
else
RandomForRsa(&ktx, label, p);
AdjustPrimeCandidate(p->buffer, p->size);
727
728 // Convert the candidate to a BN
729 if(BN_bin2bn(p->buffer, p->size, bnP) == NULL) 730 FAIL(FATAL_ERROR_INTERNAL);
731 // If this is the second prime, make sure that it differs from the 732 // first prime by at least 2^100. Since BIGNUMS use words, the check 733 // below will make sure they are different by at least 128 bits
734 if(!BN_is_zero(bnQ))
735 { // bnQ is non-zero, we have a first value 736 UINT32 *pP = (UINT32 *)(&bnP->d[4]);
737 UINT32 *pQ = (UINT32 *)(&bnQ->d[4]);
738 INT32 k = ((INT32)bnP->top) - 4;
739 for(;k > 0; k--)
740 if(*pP++ != *pQ++) 741 break;
742 // Didn't find any difference so go get a new value
743 if(k == 0)
744 continue;
745 }
746 // If PrimeSelectWithSieve returns success, bnP is a prime, 747 #ifdef RSA_DEBUG
748 if(!PrimeSelectWithSieve(bnP, ktxPtr, e, context, fieldSize, primes)) 749 #else
750 if(!PrimeSelectWithSieve(bnP, ktxPtr, e, context)) 751 #endif
752 continue; // If not, get another 753
754 // Found a prime, is this the first or second. 755 if(BN_is_zero(bnQ))
756 { // copy p to q and compute another prime in p 757 BN_copy(bnQ, bnP);
758 continue;
759 }
760 //Form the public modulus
761 if( BN_mul(bnN, bnP, bnQ, context) != 1 762 || BN_num_bits(bnN) != keySizeInBits) 763 FAIL(FATAL_ERROR_INTERNAL);
764 // Save the public modulus
765 BnTo2B(n, bnN, n->size);
766 // And one prime
767 BnTo2B(p, bnP, p->size); 768
769 #ifdef EXTENDED_CHECKS
770 // Finish by making sure that we can form the modular inverse of PHI 771 // with respect to the public exponent
772 // Compute PHI = (p - 1)(q - 1) = n - p - q + 1
773 | // Make sure that we can form the modular inverse | ||
774 | if( BN_sub(bnT, bnN, bnP) != 1 | ||
775 | || BN_sub(bnT, bnT, bnQ) != 1 | ||
776 | || BN_add_word(bnT, 1) != 1) | ||
777 | FAIL(FATAL_ERROR_INTERNAL); | ||
778 | |||
779 | // find d such that (Phi * d) mod e ==1 | ||
780 | // If there isn't then we are broken because we took the step | ||
781 | // of making sure that the prime != 1 mod e so the modular inverse | ||
782 | // must exist | ||
783 | if( BN_mod_inverse(bnT, bnE, bnT, context) == NULL | ||
784 | || BN_is_zero(bnT)) | ||
785 | FAIL(FATAL_ERROR_INTERNAL); | ||
786 | |||
787 | // And, finally, do a trial encryption decryption | ||
788 | { | ||
789 | TPM2B_TYPE(RSA_KEY, MAX_RSA_KEY_BYTES); | ||
790 | TPM2B_RSA_KEY r; | ||
791 | r.t.size = sizeof(r.t.buffer); | ||
792 | // If we are using a seed, then results must be reproducible on | each | |
793 | // call. Otherwise, just get a random number | ||
794 | if(seed == NULL) | ||
795 | _cpri GenerateRandom(keySizeInBits/8, r.t.buffer); | ||
796 | else | ||
797 | RandomForRsa(&ktx, label, &r.b); | ||
798 | |||
799 | // Make sure that the number is smaller than the public modulus | ||
800 | r.t.buffer[0] &= 0x7F; | ||
801 | // Convert | ||
802 | if( BN_bin2bn(r.t.buffer, r.t.size, bnP) == NULL | ||
803 | // Encrypt with the public exponent | ||
804 | || BN_mod_exp(bnQ, bnP, bnE, bnN, context) != 1 | ||
805 | // Decrypt with the private exponent | ||
806 | || BN_mod_exp(bnQ, bnQ, bnT, bnN, context) != 1) | ||
807 | FAIL(FATAL_ERROR_INTERNAL); | ||
808 | // If the starting and ending values are not the same, start over | )-; | |
809 | if(BN_ucmp(bnP, bnQ) != 0) | ||
810 | { | ||
811 | BN_zero(bnQ); | ||
812 | continue; | ||
813 | } |
814 }
815 #endif // EXTENDED_CHECKS
816 retVal = CRYPT_SUCCESS;
817 goto end;
818 }
819 retVal = CRYPT_FAIL;
820
821 end:
822 KDFaContextEnd(&ktx);
823
824 // Free up allocated BN values 825 BN_CTX_end(context);
826 BN_CTX_free(context);
827 return retVal;
828 }
829 #else
830 static void noFuntion( 831 void
832 )
833 {
834 pAssert(1);
835 }
836 #endif //% 837 #endif // TPM_ALG_RSA
#include "OsslCryptoEngine.h"
#ifdef RSA_KEY_SIEVE
#include "RsaKeySieve.h"
#ifdef RSA_DEBUG
UINT16 defaultFieldSize = MAX_FIELD_SIZE;
#endif
This table contains a pre-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.
const BYTE seedValues[SEED_VALUES_SIZE] = {
8 0x16, 0x29, 0xcb, 0xa4, 0x65, 0xda, 0x30, 0x6c, 9 0x99, 0x96, 0x4c, 0x53, 0xa2, 0x2d, 0x52, 0x96,
10 0x49, 0xcb, 0xb4, 0x61, 0xd8, 0x32, 0x2d, 0x99, 11 0xa6, 0x44, 0x5b, 0xa4, 0x2c, 0x93, 0x96, 0x69,
12 0xc3, 0xb0, 0x65, 0x5a, 0x32, 0x4d, 0x89, 0xb6, 13 0x48, 0x59, 0x26, 0x2d, 0xd3, 0x86, 0x61, 0xcb,
14 0xb4, 0x64, 0x9a, 0x12, 0x6d, 0x91, 0xb2, 0x4c, 15 0x5a, 0xa6, 0x0d, 0xc3, 0x96, 0x69, 0xc9, 0x34, 16 0x25, 0xda, 0x22, 0x65, 0x99, 0xb4, 0x4c, 0x1b, 17 0x86, 0x2d, 0xd3, 0x92, 0x69, 0x4a, 0xb4, 0x45,
18 0xca, 0x32, 0x69, 0x99, 0x36, 0x0c, 0x5b, 0xa6, 19 0x25, 0xd3, 0x94, 0x68, 0x8b, 0x94, 0x65, 0xd2,
20 0x32, 0x6d, 0x18, 0xb6, 0x4c, 0x4b, 0xa6, 0x29, 21 0xd1};
22 const BYTE bitsInByte[256] = {
23 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
24 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
25 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
26 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
27 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
28 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
29 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
30 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
31 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
32 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
33 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
34 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
35 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
36 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
37 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
38 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
39 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
40 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
41 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
42 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
43 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
44 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
45 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
46 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
47 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
48 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
49 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
50 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
51 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
52 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
53 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
54 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08
55 };
Following table contains a byte that is the difference between two successive primes. This reduces the table size by a factor of two. It is optimized for sequential access to the prime table which is the most common case.
When the table size is at its max, the table will have all primes less than 2^16. This is 6542 primes in 6542 bytes.
const UINT16 primeTableBytes = PRIME_DIFF_TABLE_BYTES;
#if PRIME_DIFF_TABLE_BYTES > 0
const BYTE primeDiffTable [PRIME_DIFF_TABLE_BYTES] = {
59 0x02,0x02,0x02,0x04,0x02,0x04,0x02,0x04,0x06,0x02,0x06,0x04,0x02,0x04,0x06,0x06,
60 0x02,0x06,0x04,0x02,0x06,0x04,0x06,0x08,0x04,0x02,0x04,0x02,0x04,0x0E,0x04,0x06,
61 0x02,0x0A,0x02,0x06,0x06,0x04,0x06,0x06,0x02,0x0A,0x02,0x04,0x02,0x0C,0x0C,0x04,
62 0x02,0x04,0x06,0x02,0x0A,0x06,0x06,0x06,0x02,0x06,0x04,0x02,0x0A,0x0E,0x04,0x02,
63 0x04,0x0E,0x06,0x0A,0x02,0x04,0x06,0x08,0x06,0x06,0x04,0x06,0x08,0x04,0x08,0x0A,
64 0x02,0x0A,0x02,0x06,0x04,0x06,0x08,0x04,0x02,0x04,0x0C,0x08,0x04,0x08,0x04,0x06,
65 0x0C,0x02,0x12,0x06,0x0A,0x06,0x06,0x02,0x06,0x0A,0x06,0x06,0x02,0x06,0x06,0x04,
66 0x02,0x0C,0x0A,0x02,0x04,0x06,0x06,0x02,0x0C,0x04,0x06,0x08,0x0A,0x08,0x0A,0x08,
67 0x06,0x06,0x04,0x08,0x06,0x04,0x08,0x04,0x0E,0x0A,0x0C,0x02,0x0A,0x02,0x04,0x02,
68 0x0A,0x0E,0x04,0x02,0x04,0x0E,0x04,0x02,0x04,0x14,0x04,0x08,0x0A,0x08,0x04,0x06,
69 0x06,0x0E,0x04,0x06,0x06,0x08,0x06,0x0C,0x04,0x06,0x02,0x0A,0x02,0x06,0x0A,0x02,
70 0x0A,0x02,0x06,0x12,0x04,0x02,0x04,0x06,0x06,0x08,0x06,0x06,0x16,0x02,0x0A,0x08,
71 0x0A,0x06,0x06,0x08,0x0C,0x04,0x06,0x06,0x02,0x06,0x0C,0x0A,0x12,0x02,0x04,0x06,
72 0x02,0x06,0x04,0x02,0x04,0x0C,0x02,0x06,0x22,0x06,0x06,0x08,0x12,0x0A,0x0E,0x04,
73 0x02,0x04,0x06,0x08,0x04,0x02,0x06,0x0C,0x0A,0x02,0x04,0x02,0x04,0x06,0x0C,0x0C,
74 0x08,0x0C,0x06,0x04,0x06,0x08,0x04,0x08,0x04,0x0E,0x04,0x06,0x02,0x04,0x06,0x02
75 #endif
76 // 256
77 #if PRIME_DIFF_TABLE_BYTES > 256
78 ,0x06,0x0A,0x14,0x06,0x04,0x02,0x18,0x04,0x02,0x0A,0x0C,0x02,0x0A,0x08,0x06,0x06,
79 0x06,0x12,0x06,0x04,0x02,0x0C,0x0A,0x0C,0x08,0x10,0x0E,0x06,0x04,0x02,0x04,0x02,
80 0x0A,0x0C,0x06,0x06,0x12,0x02,0x10,0x02,0x16,0x06,0x08,0x06,0x04,0x02,0x04,0x08,
81 0x06,0x0A,0x02,0x0A,0x0E,0x0A,0x06,0x0C,0x02,0x04,0x02,0x0A,0x0C,0x02,0x10,0x02,
82 0x06,0x04,0x02,0x0A,0x08,0x12,0x18,0x04,0x06,0x08,0x10,0x02,0x04,0x08,0x10,0x02,
83 0x04,0x08,0x06,0x06,0x04,0x0C,0x02,0x16,0x06,0x02,0x06,0x04,0x06,0x0E,0x06,0x04,
84 0x02,0x06,0x04,0x06,0x0C,0x06,0x06,0x0E,0x04,0x06,0x0C,0x08,0x06,0x04,0x1A,0x12,
85 0x0A,0x08,0x04,0x06,0x02,0x06,0x16,0x0C,0x02,0x10,0x08,0x04,0x0C,0x0E,0x0A,0x02,
86 0x04,0x08,0x06,0x06,0x04,0x02,0x04,0x06,0x08,0x04,0x02,0x06,0x0A,0x02,0x0A,0x08,
87 0x04,0x0E,0x0A,0x0C,0x02,0x06,0x04,0x02,0x10,0x0E,0x04,0x06,0x08,0x06,0x04,0x12,
88 0x08,0x0A,0x06,0x06,0x08,0x0A,0x0C,0x0E,0x04,0x06,0x06,0x02,0x1C,0x02,0x0A,0x08,
89 0x04,0x0E,0x04,0x08,0x0C,0x06,0x0C,0x04,0x06,0x14,0x0A,0x02,0x10,0x1A,0x04,0x02,
90 0x0C,0x06,0x04,0x0C,0x06,0x08,0x04,0x08,0x16,0x02,0x04,0x02,0x0C,0x1C,0x02,0x06,
91 0x06,0x06,0x04,0x06,0x02,0x0C,0x04,0x0C,0x02,0x0A,0x02,0x10,0x02,0x10,0x06,0x14,
92 0x10,0x08,0x04,0x02,0x04,0x02,0x16,0x08,0x0C,0x06,0x0A,0x02,0x04,0x06,0x02,0x06,
93 0x0A,0x02,0x0C,0x0A,0x02,0x0A,0x0E,0x06,0x04,0x06,0x08,0x06,0x06,0x10,0x0C,0x02
94 #endif
95 // 512
96 #if PRIME_DIFF_TABLE_BYTES > 512
97 ,0x04,0x0E,0x06,0x04,0x08,0x0A,0x08,0x06,0x06,0x16,0x06,0x02,0x0A,0x0E,0x04,0x06,
98 0x12,0x02,0x0A,0x0E,0x04,0x02,0x0A,0x0E,0x04,0x08,0x12,0x04,0x06,0x02,0x04,0x06,
99 0x02,0x0C,0x04,0x14,0x16,0x0C,0x02,0x04,0x06,0x06,0x02,0x06,0x16,0x02,0x06,0x10,
100 0x06,0x0C,0x02,0x06,0x0C,0x10,0x02,0x04,0x06,0x0E,0x04,0x02,0x12,0x18,0x0A,0x06,
101 0x02,0x0A,0x02,0x0A,0x02,0x0A,0x06,0x02,0x0A,0x02,0x0A,0x06,0x08,0x1E,0x0A,0x02,
102 0x0A,0x08,0x06,0x0A,0x12,0x06,0x0C,0x0C,0x02,0x12,0x06,0x04,0x06,0x06,0x12,0x02,
103 0x0A,0x0E,0x06,0x04,0x02,0x04,0x18,0x02,0x0C,0x06,0x10,0x08,0x06,0x06,0x12,0x10,
104 0x02,0x04,0x06,0x02,0x06,0x06,0x0A,0x06,0x0C,0x0C,0x12,0x02,0x06,0x04,0x12,0x08,
105 0x18,0x04,0x02,0x04,0x06,0x02,0x0C,0x04,0x0E,0x1E,0x0A,0x06,0x0C,0x0E,0x06,0x0A,
106 0x0C,0x02,0x04,0x06,0x08,0x06,0x0A,0x02,0x04,0x0E,0x06,0x06,0x04,0x06,0x02,0x0A,
107 0x02,0x10,0x0C,0x08,0x12,0x04,0x06,0x0C,0x02,0x06,0x06,0x06,0x1C,0x06,0x0E,0x04,
108 0x08,0x0A,0x08,0x0C,0x12,0x04,0x02,0x04,0x18,0x0C,0x06,0x02,0x10,0x06,0x06,0x0E,
109 0x0A,0x0E,0x04,0x1E,0x06,0x06,0x06,0x08,0x06,0x04,0x02,0x0C,0x06,0x04,0x02,0x06,
110 0x16,0x06,0x02,0x04,0x12,0x02,0x04,0x0C,0x02,0x06,0x04,0x1A,0x06,0x06,0x04,0x08,
111 0x0A,0x20,0x10,0x02,0x06,0x04,0x02,0x04,0x02,0x0A,0x0E,0x06,0x04,0x08,0x0A,0x06,
112 0x14,0x04,0x02,0x06,0x1E,0x04,0x08,0x0A,0x06,0x06,0x08,0x06,0x0C,0x04,0x06,0x02
113 #endif
114 // 768
115 #if PRIME_DIFF_TABLE_BYTES > 768
116 ,0x06,0x04,0x06,0x02,0x0A,0x02,0x10,0x06,0x14,0x04,0x0C,0x0E,0x1C,0x06,0x14,0x04,
117 0x12,0x08,0x06,0x04,0x06,0x0E,0x06,0x06,0x0A,0x02,0x0A,0x0C,0x08,0x0A,0x02,0x0A,
118 0x08,0x0C,0x0A,0x18,0x02,0x04,0x08,0x06,0x04,0x08,0x12,0x0A,0x06,0x06,0x02,0x06,
119 0x0A,0x0C,0x02,0x0A,0x06,0x06,0x06,0x08,0x06,0x0A,0x06,0x02,0x06,0x06,0x06,0x0A,
120 0x08,0x18,0x06,0x16,0x02,0x12,0x04,0x08,0x0A,0x1E,0x08,0x12,0x04,0x02,0x0A,0x06,
121 0x02,0x06,0x04,0x12,0x08,0x0C,0x12,0x10,0x06,0x02,0x0C,0x06,0x0A,0x02,0x0A,0x02,
122 0x06,0x0A,0x0E,0x04,0x18,0x02,0x10,0x02,0x0A,0x02,0x0A,0x14,0x04,0x02,0x04,0x08,
123 0x10,0x06,0x06,0x02,0x0C,0x10,0x08,0x04,0x06,0x1E,0x02,0x0A,0x02,0x06,0x04,0x06,
124 0x06,0x08,0x06,0x04,0x0C,0x06,0x08,0x0C,0x04,0x0E,0x0C,0x0A,0x18,0x06,0x0C,0x06,
125 0x02,0x16,0x08,0x12,0x0A,0x06,0x0E,0x04,0x02,0x06,0x0A,0x08,0x06,0x04,0x06,0x1E,
126 0x0E,0x0A,0x02,0x0C,0x0A,0x02,0x10,0x02,0x12,0x18,0x12,0x06,0x10,0x12,0x06,0x02,
127 0x12,0x04,0x06,0x02,0x0A,0x08,0x0A,0x06,0x06,0x08,0x04,0x06,0x02,0x0A,0x02,0x0C,
128 0x04,0x06,0x06,0x02,0x0C,0x04,0x0E,0x12,0x04,0x06,0x14,0x04,0x08,0x06,0x04,0x08,
129 0x04,0x0E,0x06,0x04,0x0E,0x0C,0x04,0x02,0x1E,0x04,0x18,0x06,0x06,0x0C,0x0C,0x0E,
130 0x06,0x04,0x02,0x04,0x12,0x06,0x0C,0x08,0x06,0x04,0x0C,0x02,0x0C,0x1E,0x10,0x02,
131 0x06,0x16,0x0E,0x06,0x0A,0x0C,0x06,0x02,0x04,0x08,0x0A,0x06,0x06,0x18,0x0E,0x06
132 #endif
133 // 1024
134 #if PRIME_DIFF_TABLE_BYTES > 1024
135 ,0x04,0x08,0x0C,0x12,0x0A,0x02,0x0A,0x02,0x04,0x06,0x14,0x06,0x04,0x0E,0x04,0x02,
136 0x04,0x0E,0x06,0x0C,0x18,0x0A,0x06,0x08,0x0A,0x02,0x1E,0x04,0x06,0x02,0x0C,0x04,
137 0x0E,0x06,0x22,0x0C,0x08,0x06,0x0A,0x02,0x04,0x14,0x0A,0x08,0x10,0x02,0x0A,0x0E,
138 0x04,0x02,0x0C,0x06,0x10,0x06,0x08,0x04,0x08,0x04,0x06,0x08,0x06,0x06,0x0C,0x06,
139 0x04,0x06,0x06,0x08,0x12,0x04,0x14,0x04,0x0C,0x02,0x0A,0x06,0x02,0x0A,0x0C,0x02,
140 0x04,0x14,0x06,0x1E,0x06,0x04,0x08,0x0A,0x0C,0x06,0x02,0x1C,0x02,0x06,0x04,0x02,
141 0x10,0x0C,0x02,0x06,0x0A,0x08,0x18,0x0C,0x06,0x12,0x06,0x04,0x0E,0x06,0x04,0x0C,
142 0x08,0x06,0x0C,0x04,0x06,0x0C,0x06,0x0C,0x02,0x10,0x14,0x04,0x02,0x0A,0x12,0x08,
143 0x04,0x0E,0x04,0x02,0x06,0x16,0x06,0x0E,0x06,0x06,0x0A,0x06,0x02,0x0A,0x02,0x04,
144 0x02,0x16,0x02,0x04,0x06,0x06,0x0C,0x06,0x0E,0x0A,0x0C,0x06,0x08,0x04,0x24,0x0E,
145 0x0C,0x06,0x04,0x06,0x02,0x0C,0x06,0x0C,0x10,0x02,0x0A,0x08,0x16,0x02,0x0C,0x06,
146 0x04,0x06,0x12,0x02,0x0C,0x06,0x04,0x0C,0x08,0x06,0x0C,0x04,0x06,0x0C,0x06,0x02,
147 0x0C,0x0C,0x04,0x0E,0x06,0x10,0x06,0x02,0x0A,0x08,0x12,0x06,0x22,0x02,0x1C,0x02,
148 0x16,0x06,0x02,0x0A,0x0C,0x02,0x06,0x04,0x08,0x16,0x06,0x02,0x0A,0x08,0x04,0x06,
149 0x08,0x04,0x0C,0x12,0x0C,0x14,0x04,0x06,0x06,0x08,0x04,0x02,0x10,0x0C,0x02,0x0A,
150 0x08,0x0A,0x02,0x04,0x06,0x0E,0x0C,0x16,0x08,0x1C,0x02,0x04,0x14,0x04,0x02,0x04
151 #endif
152 // 1280
153 #if PRIME_DIFF_TABLE_BYTES > 1280
154 ,0x0E,0x0A,0x0C,0x02,0x0C,0x10,0x02,0x1C,0x08,0x16,0x08,0x04,0x06,0x06,0x0E,0x04,
155 0x08,0x0C,0x06,0x06,0x04,0x14,0x04,0x12,0x02,0x0C,0x06,0x04,0x06,0x0E,0x12,0x0A,
156 0x08,0x0A,0x20,0x06,0x0A,0x06,0x06,0x02,0x06,0x10,0x06,0x02,0x0C,0x06,0x1C,0x02,
157 0x0A,0x08,0x10,0x06,0x08,0x06,0x0A,0x18,0x14,0x0A,0x02,0x0A,0x02,0x0C,0x04,0x06,
158 0x14,0x04,0x02,0x0C,0x12,0x0A,0x02,0x0A,0x02,0x04,0x14,0x10,0x1A,0x04,0x08,0x06,
159 0x04,0x0C,0x06,0x08,0x0C,0x0C,0x06,0x04,0x08,0x16,0x02,0x10,0x0E,0x0A,0x06,0x0C,
160 0x0C,0x0E,0x06,0x04,0x14,0x04,0x0C,0x06,0x02,0x06,0x06,0x10,0x08,0x16,0x02,0x1C,
161 0x08,0x06,0x04,0x14,0x04,0x0C,0x18,0x14,0x04,0x08,0x0A,0x02,0x10,0x02,0x0C,0x0C,
162 0x22,0x02,0x04,0x06,0x0C,0x06,0x06,0x08,0x06,0x04,0x02,0x06,0x18,0x04,0x14,0x0A,
163 0x06,0x06,0x0E,0x04,0x06,0x06,0x02,0x0C,0x06,0x0A,0x02,0x0A,0x06,0x14,0x04,0x1A,
164 0x04,0x02,0x06,0x16,0x02,0x18,0x04,0x06,0x02,0x04,0x06,0x18,0x06,0x08,0x04,0x02,
165 0x22,0x06,0x08,0x10,0x0C,0x02,0x0A,0x02,0x0A,0x06,0x08,0x04,0x08,0x0C,0x16,0x06,
166 0x0E,0x04,0x1A,0x04,0x02,0x0C,0x0A,0x08,0x04,0x08,0x0C,0x04,0x0E,0x06,0x10,0x06,
167 0x08,0x04,0x06,0x06,0x08,0x06,0x0A,0x0C,0x02,0x06,0x06,0x10,0x08,0x06,0x06,0x0C,
168 0x0A,0x02,0x06,0x12,0x04,0x06,0x06,0x06,0x0C,0x12,0x08,0x06,0x0A,0x08,0x12,0x04,
169 0x0E,0x06,0x12,0x0A,0x08,0x0A,0x0C,0x02,0x06,0x0C,0x0C,0x24,0x04,0x06,0x08,0x04
170 #endif
171 // 1536
172 #if PRIME_DIFF_TABLE_BYTES > 1536
173 ,0x06,0x02,0x04,0x12,0x0C,0x06,0x08,0x06,0x06,0x04,0x12,0x02,0x04,0x02,0x18,0x04,
174 0x06,0x06,0x0E,0x1E,0x06,0x04,0x06,0x0C,0x06,0x14,0x04,0x08,0x04,0x08,0x06,0x06,
175 0x04,0x1E,0x02,0x0A,0x0C,0x08,0x0A,0x08,0x18,0x06,0x0C,0x04,0x0E,0x04,0x06,0x02,
176 0x1C,0x0E,0x10,0x02,0x0C,0x06,0x04,0x14,0x0A,0x06,0x06,0x06,0x08,0x0A,0x0C,0x0E,
177 0x0A,0x0E,0x10,0x0E,0x0A,0x0E,0x06,0x10,0x06,0x08,0x06,0x10,0x14,0x0A,0x02,0x06,
178 0x04,0x02,0x04,0x0C,0x02,0x0A,0x02,0x06,0x16,0x06,0x02,0x04,0x12,0x08,0x0A,0x08,
179 0x16,0x02,0x0A,0x12,0x0E,0x04,0x02,0x04,0x12,0x02,0x04,0x06,0x08,0x0A,0x02,0x1E,
180 0x04,0x1E,0x02,0x0A,0x02,0x12,0x04,0x12,0x06,0x0E,0x0A,0x02,0x04,0x14,0x24,0x06,
181 0x04,0x06,0x0E,0x04,0x14,0x0A,0x0E,0x16,0x06,0x02,0x1E,0x0C,0x0A,0x12,0x02,0x04,
182 0x0E,0x06,0x16,0x12,0x02,0x0C,0x06,0x04,0x08,0x04,0x08,0x06,0x0A,0x02,0x0C,0x12,
183 0x0A,0x0E,0x10,0x0E,0x04,0x06,0x06,0x02,0x06,0x04,0x02,0x1C,0x02,0x1C,0x06,0x02,
184 0x04,0x06,0x0E,0x04,0x0C,0x0E,0x10,0x0E,0x04,0x06,0x08,0x06,0x04,0x06,0x06,0x06,
185 0x08,0x04,0x08,0x04,0x0E,0x10,0x08,0x06,0x04,0x0C,0x08,0x10,0x02,0x0A,0x08,0x04,
186 0x06,0x1A,0x06,0x0A,0x08,0x04,0x06,0x0C,0x0E,0x1E,0x04,0x0E,0x16,0x08,0x0C,0x04,
187 0x06,0x08,0x0A,0x06,0x0E,0x0A,0x06,0x02,0x0A,0x0C,0x0C,0x0E,0x06,0x06,0x12,0x0A,
188 0x06,0x08,0x12,0x04,0x06,0x02,0x06,0x0A,0x02,0x0A,0x08,0x06,0x06,0x0A,0x02,0x12
189 #endif
190 // 1792
191 #if PRIME_DIFF_TABLE_BYTES > 1792
192 ,0x0A,0x02,0x0C,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x0C,0x04,0x08,0x0A,0x06,0x06,0x14,
193 0x04,0x0E,0x10,0x0E,0x0A,0x08,0x0A,0x0C,0x02,0x12,0x06,0x0C,0x0A,0x0C,0x02,0x04,
194 0x02,0x0C,0x06,0x04,0x08,0x04,0x2C,0x04,0x02,0x04,0x02,0x0A,0x0C,0x06,0x06,0x0E,
195 0x04,0x06,0x06,0x06,0x08,0x06,0x24,0x12,0x04,0x06,0x02,0x0C,0x06,0x06,0x06,0x04,
196 0x0E,0x16,0x0C,0x02,0x12,0x0A,0x06,0x1A,0x18,0x04,0x02,0x04,0x02,0x04,0x0E,0x04,
197 0x06,0x06,0x08,0x10,0x0C,0x02,0x2A,0x04,0x02,0x04,0x18,0x06,0x06,0x02,0x12,0x04,
198 0x0E,0x06,0x1C,0x12,0x0E,0x06,0x0A,0x0C,0x02,0x06,0x0C,0x1E,0x06,0x04,0x06,0x06,
199 0x0E,0x04,0x02,0x18,0x04,0x06,0x06,0x1A,0x0A,0x12,0x06,0x08,0x06,0x06,0x1E,0x04,
200 0x0C,0x0C,0x02,0x10,0x02,0x06,0x04,0x0C,0x12,0x02,0x06,0x04,0x1A,0x0C,0x06,0x0C,
201 0x04,0x18,0x18,0x0C,0x06,0x02,0x0C,0x1C,0x08,0x04,0x06,0x0C,0x02,0x12,0x06,0x04,
202 0x06,0x06,0x14,0x10,0x02,0x06,0x06,0x12,0x0A,0x06,0x02,0x04,0x08,0x06,0x06,0x18,
203 0x10,0x06,0x08,0x0A,0x06,0x0E,0x16,0x08,0x10,0x06,0x02,0x0C,0x04,0x02,0x16,0x08,
204 0x12,0x22,0x02,0x06,0x12,0x04,0x06,0x06,0x08,0x0A,0x08,0x12,0x06,0x04,0x02,0x04,
205 0x08,0x10,0x02,0x0C,0x0C,0x06,0x12,0x04,0x06,0x06,0x06,0x02,0x06,0x0C,0x0A,0x14,
206 0x0C,0x12,0x04,0x06,0x02,0x10,0x02,0x0A,0x0E,0x04,0x1E,0x02,0x0A,0x0C,0x02,0x18,
207 0x06,0x10,0x08,0x0A,0x02,0x0C,0x16,0x06,0x02,0x10,0x14,0x0A,0x02,0x0C,0x0C,0x00
208 #endif
209 // 2048
210 #if PRIME_DIFF_TABLE_BYTES > 2048
211 ,0x12,0x0A,0x0C,0x06,0x02,0x0A,0x02,0x06,0x0A,0x12,0x02,0x0C,0x06,0x04,0x06,0x02,
212 0x18,0x1C,0x02,0x04,0x02,0x0A,0x02,0x10,0x0C,0x08,0x16,0x02,0x06,0x04,0x02,0x0A,
213 0x06,0x14,0x0C,0x0A,0x08,0x0C,0x06,0x06,0x06,0x04,0x12,0x02,0x04,0x0C,0x12,0x02,
214 0x0C,0x06,0x04,0x02,0x10,0x0C,0x0C,0x0E,0x04,0x08,0x12,0x04,0x0C,0x0E,0x06,0x06,
215 0x04,0x08,0x06,0x04,0x14,0x0C,0x0A,0x0E,0x04,0x02,0x10,0x02,0x0C,0x1E,0x04,0x06,
216 0x18,0x14,0x18,0x0A,0x08,0x0C,0x0A,0x0C,0x06,0x0C,0x0C,0x06,0x08,0x10,0x0E,0x06,
217 0x04,0x06,0x24,0x14,0x0A,0x1E,0x0C,0x02,0x04,0x02,0x1C,0x0C,0x0E,0x06,0x16,0x08,
218 0x04,0x12,0x06,0x0E,0x12,0x04,0x06,0x02,0x06,0x22,0x12,0x02,0x10,0x06,0x12,0x02,
219 0x18,0x04,0x02,0x06,0x0C,0x06,0x0C,0x0A,0x08,0x06,0x10,0x0C,0x08,0x0A,0x0E,0x28,
220 0x06,0x02,0x06,0x04,0x0C,0x0E,0x04,0x02,0x04,0x02,0x04,0x08,0x06,0x0A,0x06,0x06,
221 0x02,0x06,0x06,0x06,0x0C,0x06,0x18,0x0A,0x02,0x0A,0x06,0x0C,0x06,0x06,0x0E,0x06,
222 0x06,0x34,0x14,0x06,0x0A,0x02,0x0A,0x08,0x0A,0x0C,0x0C,0x02,0x06,0x04,0x0E,0x10,
223 0x08,0x0C,0x06,0x16,0x02,0x0A,0x08,0x06,0x16,0x02,0x16,0x06,0x08,0x0A,0x0C,0x0C,
224 0x02,0x0A,0x06,0x0C,0x02,0x04,0x0E,0x0A,0x02,0x06,0x12,0x04,0x0C,0x08,0x12,0x0C,
225 0x06,0x06,0x04,0x06,0x06,0x0E,0x04,0x02,0x0C,0x0C,0x04,0x06,0x12,0x12,0x0C,0x02,
226 0x10,0x0C,0x08,0x12,0x0A,0x1A,0x04,0x06,0x08,0x06,0x06,0x04,0x02,0x0A,0x14,0x04
227 #endif
228 // 2304
229 #if PRIME_DIFF_TABLE_BYTES > 2304
230 ,0x06,0x08,0x04,0x14,0x0A,0x02,0x22,0x02,0x04,0x18,0x02,0x0C,0x0C,0x0A,0x06,0x02,
231 0x0C,0x1E,0x06,0x0C,0x10,0x0C,0x02,0x16,0x12,0x0C,0x0E,0x0A,0x02,0x0C,0x0C,0x04,
232 0x02,0x04,0x06,0x0C,0x02,0x10,0x12,0x02,0x28,0x08,0x10,0x06,0x08,0x0A,0x02,0x04,
233 0x12,0x08,0x0A,0x08,0x0C,0x04,0x12,0x02,0x12,0x0A,0x02,0x04,0x02,0x04,0x08,0x1C,
234 0x02,0x06,0x16,0x0C,0x06,0x0E,0x12,0x04,0x06,0x08,0x06,0x06,0x0A,0x08,0x04,0x02,
235 0x12,0x0A,0x06,0x14,0x16,0x08,0x06,0x1E,0x04,0x02,0x04,0x12,0x06,0x1E,0x02,0x04,
236 0x08,0x06,0x04,0x06,0x0C,0x0E,0x22,0x0E,0x06,0x04,0x02,0x06,0x04,0x0E,0x04,0x02,
237 0x06,0x1C,0x02,0x04,0x06,0x08,0x0A,0x02,0x0A,0x02,0x0A,0x02,0x04,0x1E,0x02,0x0C,
238 0x0C,0x0A,0x12,0x0C,0x0E,0x0A,0x02,0x0C,0x06,0x0A,0x06,0x0E,0x0C,0x04,0x0E,0x04,
239 0x12,0x02,0x0A,0x08,0x04,0x08,0x0A,0x0C,0x12,0x12,0x08,0x06,0x12,0x10,0x0E,0x06,
240 0x06,0x0A,0x0E,0x04,0x06,0x02,0x0C,0x0C,0x04,0x06,0x06,0x0C,0x02,0x10,0x02,0x0C,
241 0x06,0x04,0x0E,0x06,0x04,0x02,0x0C,0x12,0x04,0x24,0x12,0x0C,0x0C,0x02,0x04,0x02,
242 0x04,0x08,0x0C,0x04,0x24,0x06,0x12,0x02,0x0C,0x0A,0x06,0x0C,0x18,0x08,0x06,0x06,
243 0x10,0x0C,0x02,0x12,0x0A,0x14,0x0A,0x02,0x06,0x12,0x04,0x02,0x28,0x06,0x02,0x10,
244 0x02,0x04,0x08,0x12,0x0A,0x0C,0x06,0x02,0x0A,0x08,0x04,0x06,0x0C,0x02,0x0A,0x12,
245 0x08,0x06,0x04,0x14,0x04,0x06,0x24,0x06,0x02,0x0A,0x06,0x18,0x06,0x0E,0x10,0x06
246 #endif
247 // 2560
248 #if PRIME_DIFF_TABLE_BYTES > 2560
249 ,0x12,0x02,0x0A,0x14,0x0A,0x08,0x06,0x04,0x06,0x02,0x0A,0x02,0x0C,0x04,0x02,0x04,
250 0x08,0x0A,0x06,0x0C,0x12,0x0E,0x0C,0x10,0x08,0x06,0x10,0x08,0x04,0x02,0x06,0x12,
251 0x18,0x12,0x0A,0x0C,0x02,0x04,0x0E,0x0A,0x06,0x06,0x06,0x12,0x0C,0x02,0x1C,0x12,
252 0x0E,0x10,0x0C,0x0E,0x18,0x0C,0x16,0x06,0x02,0x0A,0x08,0x04,0x02,0x04,0x0E,0x0C,
253 0x06,0x04,0x06,0x0E,0x04,0x02,0x04,0x1E,0x06,0x02,0x06,0x0A,0x02,0x1E,0x16,0x02,
254 0x04,0x06,0x08,0x06,0x06,0x10,0x0C,0x0C,0x06,0x08,0x04,0x02,0x18,0x0C,0x04,0x06,
255 0x08,0x06,0x06,0x0A,0x02,0x06,0x0C,0x1C,0x0E,0x06,0x04,0x0C,0x08,0x06,0x0C,0x04,
256 0x06,0x0E,0x06,0x0C,0x0A,0x06,0x06,0x08,0x06,0x06,0x04,0x02,0x04,0x08,0x0C,0x04,
257 0x0E,0x12,0x0A,0x02,0x10,0x06,0x14,0x06,0x0A,0x08,0x04,0x1E,0x24,0x0C,0x08,0x16,
258 0x0C,0x02,0x06,0x0C,0x10,0x06,0x06,0x02,0x12,0x04,0x1A,0x04,0x08,0x12,0x0A,0x08,
259 0x0A,0x06,0x0E,0x04,0x14,0x16,0x12,0x0C,0x08,0x1C,0x0C,0x06,0x06,0x08,0x06,0x0C,
260 0x18,0x10,0x0E,0x04,0x0E,0x0C,0x06,0x0A,0x0C,0x14,0x06,0x04,0x08,0x12,0x0C,0x12,
261 0x0A,0x02,0x04,0x14,0x0A,0x0E,0x04,0x06,0x02,0x0A,0x18,0x12,0x02,0x04,0x14,0x10,
262 0x0E,0x0A,0x0E,0x06,0x04,0x06,0x14,0x06,0x0A,0x06,0x02,0x0C,0x06,0x1E,0x0A,0x08,
263 0x06,0x04,0x06,0x08,0x28,0x02,0x04,0x02,0x0C,0x12,0x04,0x06,0x08,0x0A,0x06,0x12,
264 0x12,0x02,0x0C,0x10,0x08,0x06,0x04,0x06,0x06,0x02,0x34,0x0E,0x04,0x14,0x10,0x02
265 #endif
266 // 2816
267 #if PRIME_DIFF_TABLE_BYTES > 2816
268 ,0x04,0x06,0x0C,0x02,0x06,0x0C,0x0C,0x06,0x04,0x0E,0x0A,0x06,0x06,0x0E,0x0A,0x0E,
269 0x10,0x08,0x06,0x0C,0x04,0x08,0x16,0x06,0x02,0x12,0x16,0x06,0x02,0x12,0x06,0x10,
270 0x0E,0x0A,0x06,0x0C,0x02,0x06,0x04,0x08,0x12,0x0C,0x10,0x02,0x04,0x0E,0x04,0x08,
271 0x0C,0x0C,0x1E,0x10,0x08,0x04,0x02,0x06,0x16,0x0C,0x08,0x0A,0x06,0x06,0x06,0x0E,
272 0x06,0x12,0x0A,0x0C,0x02,0x0A,0x02,0x04,0x1A,0x04,0x0C,0x08,0x04,0x12,0x08,0x0A,
273 0x0E,0x10,0x06,0x06,0x08,0x0A,0x06,0x08,0x06,0x0C,0x0A,0x14,0x0A,0x08,0x04,0x0C,
274 0x1A,0x12,0x04,0x0C,0x12,0x06,0x1E,0x06,0x08,0x06,0x16,0x0C,0x02,0x04,0x06,0x06,
275 0x02,0x0A,0x02,0x04,0x06,0x06,0x02,0x06,0x16,0x12,0x06,0x12,0x0C,0x08,0x0C,0x06,
276 0x0A,0x0C,0x02,0x10,0x02,0x0A,0x02,0x0A,0x12,0x06,0x14,0x04,0x02,0x06,0x16,0x06,
277 0x06,0x12,0x06,0x0E,0x0C,0x10,0x02,0x06,0x06,0x04,0x0E,0x0C,0x04,0x02,0x12,0x10,
278 0x24,0x0C,0x06,0x0E,0x1C,0x02,0x0C,0x06,0x0C,0x06,0x04,0x02,0x10,0x1E,0x08,0x18,
279 0x06,0x1E,0x0A,0x02,0x12,0x04,0x06,0x0C,0x08,0x16,0x02,0x06,0x16,0x12,0x02,0x0A,
280 0x02,0x0A,0x1E,0x02,0x1C,0x06,0x0E,0x10,0x06,0x14,0x10,0x02,0x06,0x04,0x20,0x04,
281 0x02,0x04,0x06,0x02,0x0C,0x04,0x06,0x06,0x0C,0x02,0x06,0x04,0x06,0x08,0x06,0x04,
282 0x14,0x04,0x20,0x0A,0x08,0x10,0x02,0x16,0x02,0x04,0x06,0x08,0x06,0x10,0x0E,0x04,
283 0x12,0x08,0x04,0x14,0x06,0x0C,0x0C,0x06,0x0A,0x02,0x0A,0x02,0x0C,0x1C,0x0C,0x12
284 #endif
285 // 3072
286 #if PRIME_DIFF_TABLE_BYTES > 3072
287 ,0x02,0x12,0x0A,0x08,0x0A,0x30,0x02,0x04,0x06,0x08,0x0A,0x02,0x0A,0x1E,0x02,0x24,
288 0x06,0x0A,0x06,0x02,0x12,0x04,0x06,0x08,0x10,0x0E,0x10,0x06,0x0E,0x04,0x14,0x04,
289 0x06,0x02,0x0A,0x0C,0x02,0x06,0x0C,0x06,0x06,0x04,0x0C,0x02,0x06,0x04,0x0C,0x06,
290 0x08,0x04,0x02,0x06,0x12,0x0A,0x06,0x08,0x0C,0x06,0x16,0x02,0x06,0x0C,0x12,0x04,
291 0x0E,0x06,0x04,0x14,0x06,0x10,0x08,0x04,0x08,0x16,0x08,0x0C,0x06,0x06,0x10,0x0C,
292 0x12,0x1E,0x08,0x04,0x02,0x04,0x06,0x1A,0x04,0x0E,0x18,0x16,0x06,0x02,0x06,0x0A,
293 0x06,0x0E,0x06,0x06,0x0C,0x0A,0x06,0x02,0x0C,0x0A,0x0C,0x08,0x12,0x12,0x0A,0x06,
294 0x08,0x10,0x06,0x06,0x08,0x10,0x14,0x04,0x02,0x0A,0x02,0x0A,0x0C,0x06,0x08,0x06,
295 0x0A,0x14,0x0A,0x12,0x1A,0x04,0x06,0x1E,0x02,0x04,0x08,0x06,0x0C,0x0C,0x12,0x04,
296 0x08,0x16,0x06,0x02,0x0C,0x22,0x06,0x12,0x0C,0x06,0x02,0x1C,0x0E,0x10,0x0E,0x04,
297 0x0E,0x0C,0x04,0x06,0x06,0x02,0x24,0x04,0x06,0x14,0x0C,0x18,0x06,0x16,0x02,0x10,
298 0x12,0x0C,0x0C,0x12,0x02,0x06,0x06,0x06,0x04,0x06,0x0E,0x04,0x02,0x16,0x08,0x0C,
299 0x06,0x0A,0x06,0x08,0x0C,0x12,0x0C,0x06,0x0A,0x02,0x16,0x0E,0x06,0x06,0x04,0x12,
300 0x06,0x14,0x16,0x02,0x0C,0x18,0x04,0x12,0x12,0x02,0x16,0x02,0x04,0x0C,0x08,0x0C,
301 0x0A,0x0E,0x04,0x02,0x12,0x10,0x26,0x06,0x06,0x06,0x0C,0x0A,0x06,0x0C,0x08,0x06,
302 0x04,0x06,0x0E,0x1E,0x06,0x0A,0x08,0x16,0x06,0x08,0x0C,0x0A,0x02,0x0A,0x02,0x06
303 #endif
304 // 3328
305 #if PRIME_DIFF_TABLE_BYTES > 3328
306 ,0x0A,0x02,0x0A,0x0C,0x12,0x14,0x06,0x04,0x08,0x16,0x06,0x06,0x1E,0x06,0x0E,0x06,
307 0x0C,0x0C,0x06,0x0A,0x02,0x0A,0x1E,0x02,0x10,0x08,0x04,0x02,0x06,0x12,0x04,0x02,
308 0x06,0x04,0x1A,0x04,0x08,0x06,0x0A,0x02,0x04,0x06,0x08,0x04,0x06,0x1E,0x0C,0x02,
309 0x06,0x06,0x04,0x14,0x16,0x08,0x04,0x02,0x04,0x48,0x08,0x04,0x08,0x16,0x02,0x04,
310 0x0E,0x0A,0x02,0x04,0x14,0x06,0x0A,0x12,0x06,0x14,0x10,0x06,0x08,0x06,0x04,0x14,
311 0x0C,0x16,0x02,0x04,0x02,0x0C,0x0A,0x12,0x02,0x16,0x06,0x12,0x1E,0x02,0x0A,0x0E,
312 0x0A,0x08,0x10,0x32,0x06,0x0A,0x08,0x0A,0x0C,0x06,0x12,0x02,0x16,0x06,0x02,0x04,
313 0x06,0x08,0x06,0x06,0x0A,0x12,0x02,0x16,0x02,0x10,0x0E,0x0A,0x06,0x02,0x0C,0x0A,
314 0x14,0x04,0x0E,0x06,0x04,0x24,0x02,0x04,0x06,0x0C,0x02,0x04,0x0E,0x0C,0x06,0x04,
315 0x06,0x02,0x06,0x04,0x14,0x0A,0x02,0x0A,0x06,0x0C,0x02,0x18,0x0C,0x0C,0x06,0x06,
316 0x04,0x18,0x02,0x04,0x18,0x02,0x06,0x04,0x06,0x08,0x10,0x06,0x02,0x0A,0x0C,0x0E,
317 0x06,0x22,0x06,0x0E,0x06,0x04,0x02,0x1E,0x16,0x08,0x04,0x06,0x08,0x04,0x02,0x1C,
318 0x02,0x06,0x04,0x1A,0x12,0x16,0x02,0x06,0x10,0x06,0x02,0x10,0x0C,0x02,0x0C,0x04,
319 0x06,0x06,0x0E,0x0A,0x06,0x08,0x0C,0x04,0x12,0x02,0x0A,0x08,0x10,0x06,0x06,0x1E,
320 0x02,0x0A,0x12,0x02,0x0A,0x08,0x04,0x08,0x0C,0x18,0x28,0x02,0x0C,0x0A,0x06,0x0C,
321 0x02,0x0C,0x04,0x02,0x04,0x06,0x12,0x0E,0x0C,0x06,0x04,0x0E,0x1E,0x04,0x08,0x0A
322 #endif
323 // 3584
324 #if PRIME_DIFF_TABLE_BYTES > 3584
325 ,0x08,0x06,0x0A,0x12,0x08,0x04,0x0E,0x10,0x06,0x08,0x04,0x06,0x02,0x0A,0x02,0x0C,
326 0x04,0x02,0x04,0x06,0x08,0x04,0x06,0x20,0x18,0x0A,0x08,0x12,0x0A,0x02,0x06,0x0A,
327 0x02,0x04,0x12,0x06,0x0C,0x02,0x10,0x02,0x16,0x06,0x06,0x08,0x12,0x04,0x12,0x0C,
328 0x08,0x06,0x04,0x14,0x06,0x1E,0x16,0x0C,0x02,0x06,0x12,0x04,0x3E,0x04,0x02,0x0C,
329 0x06,0x0A,0x02,0x0C,0x0C,0x1C,0x02,0x04,0x0E,0x16,0x06,0x02,0x06,0x06,0x0A,0x0E,
330 0x04,0x02,0x0A,0x06,0x08,0x0A,0x0E,0x0A,0x06,0x02,0x0C,0x16,0x12,0x08,0x0A,0x12,
331 0x0C,0x02,0x0C,0x04,0x0C,0x02,0x0A,0x02,0x06,0x12,0x06,0x06,0x22,0x06,0x02,0x0C,
332 0x04,0x06,0x12,0x12,0x02,0x10,0x06,0x06,0x08,0x06,0x0A,0x12,0x08,0x0A,0x08,0x0A,
333 0x02,0x04,0x12,0x1A,0x0C,0x16,0x02,0x04,0x02,0x16,0x06,0x06,0x0E,0x10,0x06,0x14,
334 0x0A,0x0C,0x02,0x12,0x2A,0x04,0x18,0x02,0x06,0x0A,0x0C,0x02,0x06,0x0A,0x08,0x04,
335 0x06,0x0C,0x0C,0x08,0x04,0x06,0x0C,0x1E,0x14,0x06,0x18,0x06,0x0A,0x0C,0x02,0x0A,
336 0x14,0x06,0x06,0x04,0x0C,0x0E,0x0A,0x12,0x0C,0x08,0x06,0x0C,0x04,0x0E,0x0A,0x02,
337 0x0C,0x1E,0x10,0x02,0x0C,0x06,0x04,0x02,0x04,0x06,0x1A,0x04,0x12,0x02,0x04,0x06,
338 0x0E,0x36,0x06,0x34,0x02,0x10,0x06,0x06,0x0C,0x1A,0x04,0x02,0x06,0x16,0x06,0x02,
339 0x0C,0x0C,0x06,0x0A,0x12,0x02,0x0C,0x0C,0x0A,0x12,0x0C,0x06,0x08,0x06,0x0A,0x06,
340 0x08,0x04,0x02,0x04,0x14,0x18,0x06,0x06,0x0A,0x0E,0x0A,0x02,0x16,0x06,0x0E,0x0A
341 #endif
342 // 3840
343 #if PRIME_DIFF_TABLE_BYTES > 3840
344 ,0x1A,0x04,0x12,0x08,0x0C,0x0C,0x0A,0x0C,0x06,0x08,0x10,0x06,0x08,0x06,0x06,0x16,
345 0x02,0x0A,0x14,0x0A,0x06,0x2C,0x12,0x06,0x0A,0x02,0x04,0x06,0x0E,0x04,0x1A,0x04,
346 0x02,0x0C,0x0A,0x08,0x04,0x08,0x0C,0x04,0x0C,0x08,0x16,0x08,0x06,0x0A,0x12,0x06,
347 0x06,0x08,0x06,0x0C,0x04,0x08,0x12,0x0A,0x0C,0x06,0x0C,0x02,0x06,0x04,0x02,0x10,
348 0x0C,0x0C,0x0E,0x0A,0x0E,0x06,0x0A,0x0C,0x02,0x0C,0x06,0x04,0x06,0x02,0x0C,0x04,
349 0x1A,0x06,0x12,0x06,0x0A,0x06,0x02,0x12,0x0A,0x08,0x04,0x1A,0x0A,0x14,0x06,0x10,
350 0x14,0x0C,0x0A,0x08,0x0A,0x02,0x10,0x06,0x14,0x0A,0x14,0x04,0x1E,0x02,0x04,0x08,
351 0x10,0x02,0x12,0x04,0x02,0x06,0x0A,0x12,0x0C,0x0E,0x12,0x06,0x10,0x14,0x06,0x04,
352 0x08,0x06,0x04,0x06,0x0C,0x08,0x0A,0x02,0x0C,0x06,0x04,0x02,0x06,0x0A,0x02,0x10,
353 0x0C,0x0E,0x0A,0x06,0x08,0x06,0x1C,0x02,0x06,0x12,0x1E,0x22,0x02,0x10,0x0C,0x02,
354 0x12,0x10,0x06,0x08,0x0A,0x08,0x0A,0x08,0x0A,0x2C,0x06,0x06,0x04,0x14,0x04,0x02,
355 0x04,0x0E,0x1C,0x08,0x06,0x10,0x0E,0x1E,0x06,0x1E,0x04,0x0E,0x0A,0x06,0x06,0x08,
356 0x04,0x12,0x0C,0x06,0x02,0x16,0x0C,0x08,0x06,0x0C,0x04,0x0E,0x04,0x06,0x02,0x04,
357 0x12,0x14,0x06,0x10,0x26,0x10,0x02,0x04,0x06,0x02,0x28,0x2A,0x0E,0x04,0x06,0x02,
358 0x18,0x0A,0x06,0x02,0x12,0x0A,0x0C,0x02,0x10,0x02,0x06,0x10,0x06,0x08,0x04,0x02,
359 0x0A,0x06,0x08,0x0A,0x02,0x12,0x10,0x08,0x0C,0x12,0x0C,0x06,0x0C,0x0A,0x06,0x06
360 #endif
361 // 4096
362 #if PRIME_DIFF_TABLE_BYTES > 4096
363 ,0x12,0x0C,0x0E,0x04,0x02,0x0A,0x14,0x06,0x0C,0x06,0x10,0x1A,0x04,0x12,0x02,0x04,
364 0x20,0x0A,0x08,0x06,0x04,0x06,0x06,0x0E,0x06,0x12,0x04,0x02,0x12,0x0A,0x08,0x0A,
365 0x08,0x0A,0x02,0x04,0x06,0x02,0x0A,0x2A,0x08,0x0C,0x04,0x06,0x12,0x02,0x10,0x08,
366 0x04,0x02,0x0A,0x0E,0x0C,0x0A,0x14,0x04,0x08,0x0A,0x26,0x04,0x06,0x02,0x0A,0x14,
367 0x0A,0x0C,0x06,0x0C,0x1A,0x0C,0x04,0x08,0x1C,0x08,0x04,0x08,0x18,0x06,0x0A,0x08,
368 0x06,0x10,0x0C,0x08,0x0A,0x0C,0x08,0x16,0x06,0x02,0x0A,0x02,0x06,0x0A,0x06,0x06,
369 0x08,0x06,0x04,0x0E,0x1C,0x08,0x10,0x12,0x08,0x04,0x06,0x14,0x04,0x12,0x06,0x02,
370 0x18,0x18,0x06,0x06,0x0C,0x0C,0x04,0x02,0x16,0x02,0x0A,0x06,0x08,0x0C,0x04,0x14,
371 0x12,0x06,0x04,0x0C,0x18,0x06,0x06,0x36,0x08,0x06,0x04,0x1A,0x24,0x04,0x02,0x04,
372 0x1A,0x0C,0x0C,0x04,0x06,0x06,0x08,0x0C,0x0A,0x02,0x0C,0x10,0x12,0x06,0x08,0x06,
373 0x0C,0x12,0x0A,0x02,0x36,0x04,0x02,0x0A,0x1E,0x0C,0x08,0x04,0x08,0x10,0x0E,0x0C,
374 0x06,0x04,0x06,0x0C,0x06,0x02,0x04,0x0E,0x0C,0x04,0x0E,0x06,0x18,0x06,0x06,0x0A,
375 0x0C,0x0C,0x14,0x12,0x06,0x06,0x10,0x08,0x04,0x06,0x14,0x04,0x20,0x04,0x0E,0x0A,
376 0x02,0x06,0x0C,0x10,0x02,0x04,0x06,0x0C,0x02,0x0A,0x08,0x06,0x04,0x02,0x0A,0x0E,
377 0x06,0x06,0x0C,0x12,0x22,0x08,0x0A,0x06,0x18,0x06,0x02,0x0A,0x0C,0x02,0x1E,0x0A,
378 0x0E,0x0C,0x0C,0x10,0x06,0x06,0x02,0x12,0x04,0x06,0x1E,0x0E,0x04,0x06,0x06,0x02
379 #endif
380 // 4352
381 #if PRIME_DIFF_TABLE_BYTES > 4352
382 ,0x06,0x04,0x06,0x0E,0x06,0x04,0x08,0x0A,0x0C,0x06,0x20,0x0A,0x08,0x16,0x02,0x0A,
383 0x06,0x18,0x08,0x04,0x1E,0x06,0x02,0x0C,0x10,0x08,0x06,0x04,0x06,0x08,0x10,0x0E,
384 0x06,0x06,0x04,0x02,0x0A,0x0C,0x02,0x10,0x0E,0x04,0x02,0x04,0x14,0x12,0x0A,0x02,
385 0x0A,0x06,0x0C,0x1E,0x08,0x12,0x0C,0x0A,0x02,0x06,0x06,0x04,0x0C,0x0C,0x02,0x04,
386 0x0C,0x12,0x18,0x02,0x0A,0x06,0x08,0x10,0x08,0x06,0x0C,0x0A,0x0E,0x06,0x0C,0x06,
387 0x06,0x04,0x02,0x18,0x04,0x06,0x08,0x06,0x04,0x02,0x04,0x06,0x0E,0x04,0x08,0x0A,
388 0x18,0x18,0x0C,0x02,0x06,0x0C,0x16,0x1E,0x02,0x06,0x12,0x0A,0x06,0x06,0x08,0x04,
389 0x02,0x06,0x0A,0x08,0x0A,0x06,0x08,0x10,0x06,0x0E,0x06,0x04,0x18,0x08,0x0A,0x02,
390 0x0C,0x06,0x04,0x24,0x02,0x16,0x06,0x08,0x06,0x0A,0x08,0x06,0x0C,0x0A,0x0E,0x0A,
391 0x06,0x12,0x0C,0x02,0x0C,0x04,0x1A,0x0A,0x0E,0x10,0x12,0x08,0x12,0x0C,0x0C,0x06,
392 0x10,0x0E,0x18,0x0A,0x0C,0x08,0x16,0x06,0x02,0x0A,0x3C,0x06,0x02,0x04,0x08,0x10,
393 0x0E,0x0A,0x06,0x18,0x06,0x0C,0x12,0x18,0x02,0x1E,0x04,0x02,0x0C,0x06,0x0A,0x02,
394 0x04,0x0E,0x06,0x10,0x02,0x0A,0x08,0x16,0x14,0x06,0x04,0x20,0x06,0x12,0x04,0x02,
395 0x04,0x02,0x04,0x08,0x34,0x0E,0x16,0x02,0x16,0x14,0x0A,0x08,0x0A,0x02,0x06,0x04,
396 0x0E,0x04,0x06,0x14,0x04,0x06,0x02,0x0C,0x0C,0x06,0x0C,0x10,0x02,0x0C,0x0A,0x08,
397 0x04,0x06,0x02,0x1C,0x0C,0x08,0x0A,0x0C,0x02,0x04,0x0E,0x1C,0x08,0x06,0x04,0x02
398 #endif
399 // 4608
400 #if PRIME_DIFF_TABLE_BYTES > 4608
401 ,0x04,0x06,0x02,0x0C,0x3A,0x06,0x0E,0x0A,0x02,0x06,0x1C,0x20,0x04,0x1E,0x08,0x06,
402 0x04,0x06,0x0C,0x0C,0x02,0x04,0x06,0x06,0x0E,0x10,0x08,0x1E,0x04,0x02,0x0A,0x08,
403 0x06,0x04,0x06,0x1A,0x04,0x0C,0x02,0x0A,0x12,0x0C,0x0C,0x12,0x02,0x04,0x0C,0x08,
404 0x0C,0x0A,0x14,0x04,0x08,0x10,0x0C,0x08,0x06,0x10,0x08,0x0A,0x0C,0x0E,0x06,0x04,
405 0x08,0x0C,0x04,0x14,0x06,0x28,0x08,0x10,0x06,0x24,0x02,0x06,0x04,0x06,0x02,0x16,
406 0x12,0x02,0x0A,0x06,0x24,0x0E,0x0C,0x04,0x12,0x08,0x04,0x0E,0x0A,0x02,0x0A,0x08,
407 0x04,0x02,0x12,0x10,0x0C,0x0E,0x0A,0x0E,0x06,0x06,0x2A,0x0A,0x06,0x06,0x14,0x0A,
408 0x08,0x0C,0x04,0x0C,0x12,0x02,0x0A,0x0E,0x12,0x0A,0x12,0x08,0x06,0x04,0x0E,0x06,
409 0x0A,0x1E,0x0E,0x06,0x06,0x04,0x0C,0x26,0x04,0x02,0x04,0x06,0x08,0x0C,0x0A,0x06,
410 0x12,0x06,0x32,0x06,0x04,0x06,0x0C,0x08,0x0A,0x20,0x06,0x16,0x02,0x0A,0x0C,0x12,
411 0x02,0x06,0x04,0x1E,0x08,0x06,0x06,0x12,0x0A,0x02,0x04,0x0C,0x14,0x0A,0x08,0x18,
412 0x0A,0x02,0x06,0x16,0x06,0x02,0x12,0x0A,0x0C,0x02,0x1E,0x12,0x0C,0x1C,0x02,0x06,
413 0x04,0x06,0x0E,0x06,0x0C,0x0A,0x08,0x04,0x0C,0x1A,0x0A,0x08,0x06,0x10,0x02,0x0A,
414 0x12,0x0E,0x06,0x04,0x06,0x0E,0x10,0x02,0x06,0x04,0x0C,0x14,0x04,0x14,0x04,0x06,
415 0x0C,0x02,0x24,0x04,0x06,0x02,0x0A,0x02,0x16,0x08,0x06,0x0A,0x0C,0x0C,0x12,0x0E,
416 0x18,0x24,0x04,0x14,0x18,0x0A,0x06,0x02,0x1C,0x06,0x12,0x08,0x04,0x06,0x08,0x06
417 #endif
418 // 4864
419 #if PRIME_DIFF_TABLE_BYTES > 4864
420 ,0x04,0x02,0x0C,0x1C,0x12,0x0E,0x10,0x0E,0x12,0x0A,0x08,0x06,0x04,0x06,0x06,0x08,
421 0x16,0x0C,0x02,0x0A,0x12,0x06,0x02,0x12,0x0A,0x02,0x0C,0x0A,0x12,0x20,0x06,0x04,
422 0x06,0x06,0x08,0x06,0x06,0x0A,0x14,0x06,0x0C,0x0A,0x08,0x0A,0x0E,0x06,0x0A,0x0E,
423 0x04,0x02,0x16,0x12,0x02,0x0A,0x02,0x04,0x14,0x04,0x02,0x22,0x02,0x0C,0x06,0x0A,
424 0x02,0x0A,0x12,0x06,0x0E,0x0C,0x0C,0x16,0x08,0x06,0x10,0x06,0x08,0x04,0x0C,0x06,
425 0x08,0x04,0x24,0x06,0x06,0x14,0x18,0x06,0x0C,0x12,0x0A,0x02,0x0A,0x1A,0x06,0x10,
426 0x08,0x06,0x04,0x18,0x12,0x08,0x0C,0x0C,0x0A,0x12,0x0C,0x02,0x18,0x04,0x0C,0x12,
427 0x0C,0x0E,0x0A,0x02,0x04,0x18,0x0C,0x0E,0x0A,0x06,0x02,0x06,0x04,0x06,0x1A,0x04,
428 0x06,0x06,0x02,0x16,0x08,0x12,0x04,0x12,0x08,0x04,0x18,0x02,0x0C,0x0C,0x04,0x02,
429 0x34,0x02,0x12,0x06,0x04,0x06,0x0C,0x02,0x06,0x0C,0x0A,0x08,0x04,0x02,0x18,0x0A,
430 0x02,0x0A,0x02,0x0C,0x06,0x12,0x28,0x06,0x14,0x10,0x02,0x0C,0x06,0x0A,0x0C,0x02,
431 0x04,0x06,0x0E,0x0C,0x0C,0x16,0x06,0x08,0x04,0x02,0x10,0x12,0x0C,0x02,0x06,0x10,
432 0x06,0x02,0x06,0x04,0x0C,0x1E,0x08,0x10,0x02,0x12,0x0A,0x18,0x02,0x06,0x18,0x04,
433 0x02,0x16,0x02,0x10,0x02,0x06,0x0C,0x04,0x12,0x08,0x04,0x0E,0x04,0x12,0x18,0x06,
434 0x02,0x06,0x0A,0x02,0x0A,0x26,0x06,0x0A,0x0E,0x06,0x06,0x18,0x04,0x02,0x0C,0x10,
435 0x0E,0x10,0x0C,0x02,0x06,0x0A,0x1A,0x04,0x02,0x0C,0x06,0x04,0x0C,0x08,0x0C,0x0A
436 #endif
437 // 5120
438 #if PRIME_DIFF_TABLE_BYTES > 5120
439 ,0x12,0x06,0x0E,0x1C,0x02,0x06,0x0A,0x02,0x04,0x0E,0x22,0x02,0x06,0x16,0x02,0x0A,
440 0x0E,0x04,0x02,0x10,0x08,0x0A,0x06,0x08,0x0A,0x08,0x04,0x06,0x02,0x10,0x06,0x06,
441 0x12,0x1E,0x0E,0x06,0x04,0x1E,0x02,0x0A,0x0E,0x04,0x14,0x0A,0x08,0x04,0x08,0x12,
442 0x04,0x0E,0x06,0x04,0x18,0x06,0x06,0x12,0x12,0x02,0x24,0x06,0x0A,0x0E,0x0C,0x04,
443 0x06,0x02,0x1E,0x06,0x04,0x02,0x06,0x1C,0x14,0x04,0x14,0x0C,0x18,0x10,0x12,0x0C,
444 0x0E,0x06,0x04,0x0C,0x20,0x0C,0x06,0x0A,0x08,0x0A,0x06,0x12,0x02,0x10,0x0E,0x06,
445 0x16,0x06,0x0C,0x02,0x12,0x04,0x08,0x1E,0x0C,0x04,0x0C,0x02,0x0A,0x26,0x16,0x02,
446 0x04,0x0E,0x06,0x0C,0x18,0x04,0x02,0x04,0x0E,0x0C,0x0A,0x02,0x10,0x06,0x14,0x04,
447 0x14,0x16,0x0C,0x02,0x04,0x02,0x0C,0x16,0x18,0x06,0x06,0x02,0x06,0x04,0x06,0x02,
448 0x0A,0x0C,0x0C,0x06,0x02,0x06,0x10,0x08,0x06,0x04,0x12,0x0C,0x0C,0x0E,0x04,0x0C,
449 0x06,0x08,0x06,0x12,0x06,0x0A,0x0C,0x0E,0x06,0x04,0x08,0x16,0x06,0x02,0x1C,0x12,
450 0x02,0x12,0x0A,0x06,0x0E,0x0A,0x02,0x0A,0x0E,0x06,0x0A,0x02,0x16,0x06,0x08,0x06,
451 0x10,0x0C,0x08,0x16,0x02,0x04,0x0E,0x12,0x0C,0x06,0x18,0x06,0x0A,0x02,0x0C,0x16,
452 0x12,0x06,0x14,0x06,0x0A,0x0E,0x04,0x02,0x06,0x0C,0x16,0x0E,0x0C,0x04,0x06,0x08,
453 0x16,0x02,0x0A,0x0C,0x08,0x28,0x02,0x06,0x0A,0x08,0x04,0x2A,0x14,0x04,0x20,0x0C,
454 0x0A,0x06,0x0C,0x0C,0x02,0x0A,0x08,0x06,0x04,0x08,0x04,0x1A,0x12,0x04,0x08,0x1C
455 #endif
456 // 5376
457 #if PRIME_DIFF_TABLE_BYTES > 5376
458 ,0x06,0x12,0x06,0x0C,0x02,0x0A,0x06,0x06,0x0E,0x0A,0x0C,0x0E,0x18,0x06,0x04,0x14,
459 0x16,0x02,0x12,0x04,0x06,0x0C,0x02,0x10,0x12,0x0E,0x06,0x06,0x04,0x06,0x08,0x12,
460 0x04,0x0E,0x1E,0x04,0x12,0x08,0x0A,0x02,0x04,0x08,0x0C,0x04,0x0C,0x12,0x02,0x0C,
461 0x0A,0x02,0x10,0x08,0x04,0x1E,0x02,0x06,0x1C,0x02,0x0A,0x02,0x12,0x0A,0x0E,0x04,
462 0x1A,0x06,0x12,0x04,0x14,0x06,0x04,0x08,0x12,0x04,0x0C,0x1A,0x18,0x04,0x14,0x16,
463 0x02,0x12,0x16,0x02,0x04,0x0C,0x02,0x06,0x06,0x06,0x04,0x06,0x0E,0x04,0x18,0x0C,
464 0x06,0x12,0x02,0x0C,0x1C,0x0E,0x04,0x06,0x08,0x16,0x06,0x0C,0x12,0x08,0x04,0x14,
465 0x06,0x04,0x06,0x02,0x12,0x06,0x04,0x0C,0x0C,0x08,0x1C,0x06,0x08,0x0A,0x02,0x18,
466 0x0C,0x0A,0x18,0x08,0x0A,0x14,0x0C,0x06,0x0C,0x0C,0x04,0x0E,0x0C,0x18,0x22,0x12,
467 0x08,0x0A,0x06,0x12,0x08,0x04,0x08,0x10,0x0E,0x06,0x04,0x06,0x18,0x02,0x06,0x04,
468 0x06,0x02,0x10,0x06,0x06,0x14,0x18,0x04,0x02,0x04,0x0E,0x04,0x12,0x02,0x06,0x0C,
469 0x04,0x0E,0x04,0x02,0x12,0x10,0x06,0x06,0x02,0x10,0x14,0x06,0x06,0x1E,0x04,0x08,
470 0x06,0x18,0x10,0x06,0x06,0x08,0x0C,0x1E,0x04,0x12,0x12,0x08,0x04,0x1A,0x0A,0x02,
471 0x16,0x08,0x0A,0x0E,0x06,0x04,0x12,0x08,0x0C,0x1C,0x02,0x06,0x04,0x0C,0x06,0x18,
472 0x06,0x08,0x0A,0x14,0x10,0x08,0x1E,0x06,0x06,0x04,0x02,0x0A,0x0E,0x06,0x0A,0x20,
473 0x16,0x12,0x02,0x04,0x02,0x04,0x08,0x16,0x08,0x12,0x0C,0x1C,0x02,0x10,0x0C,0x12
474 #endif
475 // 5632
476 #if PRIME_DIFF_TABLE_BYTES > 5632
477 ,0x0E,0x0A,0x12,0x0C,0x06,0x20,0x0A,0x0E,0x06,0x0A,0x02,0x0A,0x02,0x06,0x16,0x02,
478 0x04,0x06,0x08,0x0A,0x06,0x0E,0x06,0x04,0x0C,0x1E,0x18,0x06,0x06,0x08,0x06,0x04,
479 0x02,0x04,0x06,0x08,0x06,0x06,0x16,0x12,0x08,0x04,0x02,0x12,0x06,0x04,0x02,0x10,
480 0x12,0x14,0x0A,0x06,0x06,0x1E,0x02,0x0C,0x1C,0x06,0x06,0x06,0x02,0x0C,0x0A,0x08,
481 0x12,0x12,0x04,0x08,0x12,0x0A,0x02,0x1C,0x02,0x0A,0x0E,0x04,0x02,0x1E,0x0C,0x16,
482 0x1A,0x0A,0x08,0x06,0x0A,0x08,0x10,0x0E,0x06,0x06,0x0A,0x0E,0x06,0x04,0x02,0x0A,
483 0x0C,0x02,0x06,0x0A,0x08,0x04,0x02,0x0A,0x1A,0x16,0x06,0x02,0x0C,0x12,0x04,0x1A,
484 0x04,0x08,0x0A,0x06,0x0E,0x0A,0x02,0x12,0x06,0x0A,0x14,0x06,0x06,0x04,0x18,0x02,
485 0x04,0x08,0x06,0x10,0x0E,0x10,0x12,0x02,0x04,0x0C,0x02,0x0A,0x02,0x06,0x0C,0x0A,
486 0x06,0x06,0x14,0x06,0x04,0x06,0x26,0x04,0x06,0x0C,0x0E,0x04,0x0C,0x08,0x0A,0x0C,
487 0x0C,0x08,0x04,0x06,0x0E,0x0A,0x06,0x0C,0x02,0x0A,0x12,0x02,0x12,0x0A,0x08,0x0A,
488 0x02,0x0C,0x04,0x0E,0x1C,0x02,0x10,0x02,0x12,0x06,0x0A,0x06,0x08,0x10,0x0E,0x1E,
489 0x0A,0x14,0x06,0x0A,0x18,0x02,0x1C,0x02,0x0C,0x10,0x06,0x08,0x24,0x04,0x08,0x04,
490 0x0E,0x0C,0x0A,0x08,0x0C,0x04,0x06,0x08,0x04,0x06,0x0E,0x16,0x08,0x06,0x04,0x02,
491 0x0A,0x06,0x14,0x0A,0x08,0x06,0x06,0x16,0x12,0x02,0x10,0x06,0x14,0x04,0x1A,0x04,
492 0x0E,0x16,0x0E,0x04,0x0C,0x06,0x08,0x04,0x06,0x06,0x1A,0x0A,0x02,0x12,0x12,0x04
493 #endif
494 // 5888
495 #if PRIME_DIFF_TABLE_BYTES > 5888
496 ,0x02,0x10,0x02,0x12,0x04,0x06,0x08,0x04,0x06,0x0C,0x02,0x06,0x06,0x1C,0x26,0x04,
497 0x08,0x10,0x1A,0x04,0x02,0x0A,0x0C,0x02,0x0A,0x08,0x06,0x0A,0x0C,0x02,0x0A,0x02,
498 0x18,0x04,0x1E,0x1A,0x06,0x06,0x12,0x06,0x06,0x16,0x02,0x0A,0x12,0x1A,0x04,0x12,
499 0x08,0x06,0x06,0x0C,0x10,0x06,0x08,0x10,0x06,0x08,0x10,0x02,0x2A,0x3A,0x08,0x04,
500 0x06,0x02,0x04,0x08,0x10,0x06,0x14,0x04,0x0C,0x0C,0x06,0x0C,0x02,0x0A,0x02,0x06,
501 0x16,0x02,0x0A,0x06,0x08,0x06,0x0A,0x0E,0x06,0x06,0x04,0x12,0x08,0x0A,0x08,0x10,
502 0x0E,0x0A,0x02,0x0A,0x02,0x0C,0x06,0x04,0x14,0x0A,0x08,0x34,0x08,0x0A,0x06,0x02,
503 0x0A,0x08,0x0A,0x06,0x06,0x08,0x0A,0x02,0x16,0x02,0x04,0x06,0x0E,0x04,0x02,0x18,
504 0x0C,0x04,0x1A,0x12,0x04,0x06,0x0E,0x1E,0x06,0x04,0x06,0x02,0x16,0x08,0x04,0x06,
505 0x02,0x16,0x06,0x08,0x10,0x06,0x0E,0x04,0x06,0x12,0x08,0x0C,0x06,0x0C,0x18,0x1E,
506 0x10,0x08,0x22,0x08,0x16,0x06,0x0E,0x0A,0x12,0x0E,0x04,0x0C,0x08,0x04,0x24,0x06,
507 0x06,0x02,0x0A,0x02,0x04,0x14,0x06,0x06,0x0A,0x0C,0x06,0x02,0x28,0x08,0x06,0x1C,
508 0x06,0x02,0x0C,0x12,0x04,0x18,0x0E,0x06,0x06,0x0A,0x14,0x0A,0x0E,0x10,0x0E,0x10,
509 0x06,0x08,0x24,0x04,0x0C,0x0C,0x06,0x0C,0x32,0x0C,0x06,0x04,0x06,0x06,0x08,0x06,
510 0x0A,0x02,0x0A,0x02,0x12,0x0A,0x0E,0x10,0x08,0x06,0x04,0x14,0x04,0x02,0x0A,0x06,
511 0x0E,0x12,0x0A,0x26,0x0A,0x12,0x02,0x0A,0x02,0x0C,0x04,0x02,0x04,0x0E,0x06,0x0A
512 #endif
513 // 6144
514 #if PRIME_DIFF_TABLE_BYTES > 6144
515 ,0x08,0x28,0x06,0x14,0x04,0x0C,0x08,0x06,0x22,0x08,0x16,0x08,0x0C,0x0A,0x02,0x10,
516 0x2A,0x0C,0x08,0x16,0x08,0x16,0x08,0x06,0x22,0x02,0x06,0x04,0x0E,0x06,0x10,0x02,
517 0x16,0x06,0x08,0x18,0x16,0x06,0x02,0x0C,0x04,0x06,0x0E,0x04,0x08,0x18,0x04,0x06,
518 0x06,0x02,0x16,0x14,0x06,0x04,0x0E,0x04,0x06,0x06,0x08,0x06,0x0A,0x06,0x08,0x06,
519 0x10,0x0E,0x06,0x06,0x16,0x06,0x18,0x20,0x06,0x12,0x06,0x12,0x0A,0x08,0x1E,0x12,
520 0x06,0x10,0x0C,0x06,0x0C,0x02,0x06,0x04,0x0C,0x08,0x06,0x16,0x08,0x06,0x04,0x0E,
521 0x0A,0x12,0x14,0x0A,0x02,0x06,0x04,0x02,0x1C,0x12,0x02,0x0A,0x06,0x06,0x06,0x0E,
522 0x28,0x18,0x02,0x04,0x08,0x0C,0x04,0x14,0x04,0x20,0x12,0x10,0x06,0x24,0x08,0x06,
523 0x04,0x06,0x0E,0x04,0x06,0x1A,0x06,0x0A,0x0E,0x12,0x0A,0x06,0x06,0x0E,0x0A,0x06,
524 0x06,0x0E,0x06,0x18,0x04,0x0E,0x16,0x08,0x0C,0x0A,0x08,0x0C,0x12,0x0A,0x12,0x08,
525 0x18,0x0A,0x08,0x04,0x18,0x06,0x12,0x06,0x02,0x0A,0x1E,0x02,0x0A,0x02,0x04,0x02,
526 0x28,0x02,0x1C,0x08,0x06,0x06,0x12,0x06,0x0A,0x0E,0x04,0x12,0x1E,0x12,0x02,0x0C,
527 0x1E,0x06,0x1E,0x04,0x12,0x0C,0x02,0x04,0x0E,0x06,0x0A,0x06,0x08,0x06,0x0A,0x0C,
528 0x02,0x06,0x0C,0x0A,0x02,0x12,0x04,0x14,0x04,0x06,0x0E,0x06,0x06,0x16,0x06,0x06,
529 0x08,0x12,0x12,0x0A,0x02,0x0A,0x02,0x06,0x04,0x06,0x0C,0x12,0x02,0x0A,0x08,0x04,
530 0x12,0x02,0x06,0x06,0x06,0x0A,0x08,0x0A,0x06,0x12,0x0C,0x08,0x0C,0x06,0x04,0x06
531 #endif
532 // 6400
533 #if PRIME_DIFF_TABLE_BYTES > 6400
534 ,0x0E,0x10,0x02,0x0C,0x04,0x06,0x26,0x06,0x06,0x10,0x14,0x1C,0x14,0x0A,0x06,0x06,
535 0x0E,0x04,0x1A,0x04,0x0E,0x0A,0x12,0x0E,0x1C,0x02,0x04,0x0E,0x10,0x02,0x1C,0x06,
536 0x08,0x06,0x22,0x08,0x04,0x12,0x02,0x10,0x08,0x06,0x28,0x08,0x12,0x04,0x1E,0x06,
537 0x0C,0x02,0x1E,0x06,0x0A,0x0E,0x28,0x0E,0x0A,0x02,0x0C,0x0A,0x08,0x04,0x08,0x06,
538 0x06,0x1C,0x02,0x04,0x0C,0x0E,0x10,0x08,0x1E,0x10,0x12,0x02,0x0A,0x12,0x06,0x20,
539 0x04,0x12,0x06,0x02,0x0C,0x0A,0x12,0x02,0x06,0x0A,0x0E,0x12,0x1C,0x06,0x08,0x10,
540 0x02,0x04,0x14,0x0A,0x08,0x12,0x0A,0x02,0x0A,0x08,0x04,0x06,0x0C,0x06,0x14,0x04,
541 0x02,0x06,0x04,0x14,0x0A,0x1A,0x12,0x0A,0x02,0x12,0x06,0x10,0x0E,0x04,0x1A,0x04,
542 0x0E,0x0A,0x0C,0x0E,0x06,0x06,0x04,0x0E,0x0A,0x02,0x1E,0x12,0x16,0x02
543 #endif
544 // 6542
545 #if PRIME_DIFF_TABLE_BYTES > 0 546 };
#endif
#if defined RSA_INSTRUMENT || defined RSA_DEBUG
UINT32 failedAtIteration[10];
UINT32 MillerRabinTrials;
UINT32 totalFields;
UINT32 emptyFields;
UINT32 noPrimeFields;
UINT16 lastSievePrime;
UINT32 primesChecked;
#endif
Only want this table when doing debug of the prime number stuff This is a table of the first 2048 primes and takes 4096 bytes
#ifdef RSA_DEBUG
const int16 primes[NUM_PRIMES]=
559 {
560 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
561 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131,
562 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
563 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
564 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
565 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
566 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613,
567 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719,
568 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827,
569 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
570 947, 953, 967, 971, 977, 983, 991, 997,1009,1013,1019,1021,1031,1033,1039,1049,
571 | 1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163, |
572 | 1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283, |
573 | 1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423, |
574 | 1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511, |
575 | 1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619, |
576 | 1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747, |
577 | 1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877, |
578 | 1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003, |
579 | 2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129, |
580 | 2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267, |
581 | 2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377, |
582 | 2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503, |
583 | 2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657, |
584 | 2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741, |
585 | 2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861, |
586 | 2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011, |
587 | 3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167, |
588 | 3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301, |
589 | 3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413, |
590 | 3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541, |
591 | 3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671, |
592 | 3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797, |
593 | 3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923, |
594 | 3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057, |
595 | 4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211, |
596 | 4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337, |
597 | 4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481, |
598 | 4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621, |
599 | 4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751, |
600 | 4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909, |
601 | 4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011, |
602 | 5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167, |
603 | 5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309, |
604 | 5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443, |
605 | 5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573, |
606 | 5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711, |
607 | 5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849, |
608 | 5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007, |
609 | 6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133, |
610 | 6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271, |
611 | 6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379, |
612 | 6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563, |
613 | 6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701, |
614 | 6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833, |
615 | 6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971, |
616 | 6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121, |
617 | 7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253, |
618 | 7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457, |
619 | 7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561, |
620 | 7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691, |
621 | 7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853, |
622 | 7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009, |
623 | 8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161, |
624 | 8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291, |
625 | 8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443, |
626 | 8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609, |
627 | 8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731, |
628 | 8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861, |
629 | 8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011, |
630 | 9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161, |
631 | 9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311, |
632 | 9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433, |
633 | 9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587, |
634 | 9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733, |
635 | 9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857, |
636 | 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, |
637 | 9931, 9941, 9949, 9967, 9973,10007,10009,10037, |
638 | 10039,10061,10067,10069,10079,10091,10093,10099, |
639 | 10103,10111,10133,10139,10141,10151,10159,10163, |
640 | 10169,10177,10181,10193,10211,10223,10243,10247, |
641 | 10253,10259,10267,10271,10273,10289,10301,10303, |
642 | 10313,10321,10331,10333,10337,10343,10357,10369, |
643 | 10391,10399,10427,10429,10433,10453,10457,10459, |
644 | 10463,10477,10487,10499,10501,10513,10529,10531, |
645 | 10559,10567,10589,10597,10601,10607,10613,10627, |
646 | 10631,10639,10651,10657,10663,10667,10687,10691, |
647 | 10709,10711,10723,10729,10733,10739,10753,10771, |
648 | 10781,10789,10799,10831,10837,10847,10853,10859, |
649 | 10861,10867,10883,10889,10891,10903,10909,10937, |
650 | 10939,10949,10957,10973,10979,10987,10993,11003, |
651 | 11027,11047,11057,11059,11069,11071,11083,11087, |
652 | 11093,11113,11117,11119,11131,11149,11159,11161, |
653 | 11171,11173,11177,11197,11213,11239,11243,11251, |
654 | 11257,11261,11273,11279,11287,11299,11311,11317, |
655 | 11321,11329,11351,11353,11369,11383,11393,11399, |
656 | 11411,11423,11437,11443,11447,11467,11471,11483, |
657 | 11489,11491,11497,11503,11519,11527,11549,11551, |
658 | 11579,11587,11593,11597,11617,11621,11633,11657, |
659 | 11677,11681,11689,11699,11701,11717,11719,11731, |
660 | 11743,11777,11779,11783,11789,11801,11807,11813, |
661 | 11821,11827,11831,11833,11839,11863,11867,11887, |
662 | 11897,11903,11909,11923,11927,11933,11939,11941, |
663 | 11953,11959,11969,11971,11981,11987,12007,12011, |
664 | 12037,12041,12043,12049,12071,12073,12097,12101, |
665 | 12107,12109,12113,12119,12143,12149,12157,12161, |
666 | 12163,12197,12203,12211,12227,12239,12241,12251, |
667 | 12253,12263,12269,12277,12281,12289,12301,12323, |
668 | 12329,12343,12347,12373,12377,12379,12391,12401, |
669 | 12409,12413,12421,12433,12437,12451,12457,12473, |
670 | 12479,12487,12491,12497,12503,12511,12517,12527, |
671 | 12539,12541,12547,12553,12569,12577,12583,12589, |
672 | 12601,12611,12613,12619,12637,12641,12647,12653, |
673 | 12659,12671,12689,12697,12703,12713,12721,12739, |
674 | 12743,12757,12763,12781,12791,12799,12809,12821, |
675 | 12823,12829,12841,12853,12889,12893,12899,12907, |
676 | 12911,12917,12919,12923,12941,12953,12959,12967, |
677 | 12973,12979,12983,13001,13003,13007,13009,13033, |
678 | 13037,13043,13049,13063,13093,13099,13103,13109, |
679 | 13121,13127,13147,13151,13159,13163,13171,13177, |
680 | 13183,13187,13217,13219,13229,13241,13249,13259, |
681 | 13267,13291,13297,13309,13313,13327,13331,13337, |
682 | 13339,13367,13381,13397,13399,13411,13417,13421, |
683 | 13441,13451,13457,13463,13469,13477,13487,13499, |
684 | 13513,13523,13537,13553,13567,13577,13591,13597, |
685 | 13613,13619,13627,13633,13649,13669,13679,13681, |
686 | 13687,13691,13693,13697,13709,13711,13721,13723, |
687 | 13729,13751,13757,13759,13763,13781,13789,13799, |
688 | 13807,13829,13831,13841,13859,13873,13877,13879, |
689 | 13883,13901,13903,13907,13913,13921,13931,13933, |
690 | 13963,13967,13997,13999,14009,14011,14029,14033, |
691 | 14051,14057,14071,14081,14083,14087,14107,14143, |
692 | 14149,14153,14159,14173,14177,14197,14207,14221, |
693 | 14243,14249,14251,14281,14293,14303,14321,14323, |
694 | 14327,14341,14347,14369,14387,14389,14401,14407, |
695 | 14411,14419,14423,14431,14437,14447,14449,14461, |
696 | 14479,14489,14503,14519,14533,14537,14543,14549, |
697 | 14551,14557,14561,14563,14591,14593,14621,14627, |
698 | 14629,14633,14639,14653,14657,14669,14683,14699, |
699 | 14713,14717,14723,14731,14737,14741,14747,14753, |
700 | 14759,14767,14771,14779,14783,14797,14813,14821, |
701 | 14827,14831,14843,14851,14867,14869,14879,14887, |
702 | 14891,14897,14923,14929,14939,14947,14951,14957, |
703 | 14969,14983,15013,15017,15031,15053,15061,15073, |
704 | 15077,15083,15091,15101,15107,15121,15131,15137, |
705 | 15139,15149,15161,15173,15187,15193,15199,15217, |
706 | 15227,15233,15241,15259,15263,15269,15271,15277, |
707 | 15287,15289,15299,15307,15313,15319,15329,15331, |
708 | 15349,15359,15361,15373,15377,15383,15391,15401, |
709 | 15413,15427,15439,15443,15451,15461,15467,15473, |
710 | 15493,15497,15511,15527,15541,15551,15559,15569, |
711 | 15581,15583,15601,15607,15619,15629,15641,15643, |
712 | 15647,15649,15661,15667,15671,15679,15683,15727, |
713 | 15731,15733,15737,15739,15749,15761,15767,15773, |
714 | 15787,15791,15797,15803,15809,15817,15823,15859, |
715 | 15877,15881,15887,15889,15901,15907,15913,15919, |
716 | 15923,15937,15959,15971,15973,15991,16001,16007, |
717 | 16033,16057,16061,16063,16067,16069,16073,16087, |
718 | 16091,16097,16103,16111,16127,16139,16141,16183, |
719 | 16187,16189,16193,16217,16223,16229,16231,16249, |
720 | 16253,16267,16273,16301,16319,16333,16339,16349, |
721 | 16361,16363,16369,16381,16411,16417,16421,16427, |
722 | 16433,16447,16451,16453,16477,16481,16487,16493, |
723 | 16519,16529,16547,16553,16561,16567,16573,16603, |
724 | 16607,16619,16631,16633,16649,16651,16657,16661, |
725 | 16673,16691,16693,16699,16703,16729,16741,16747, |
726 | 16759,16763,16787,16811,16823,16829,16831,16843, |
727 | 16871,16879,16883,16889,16901,16903,16921,16927, |
728 | 16931,16937,16943,16963,16979,16981,16987,16993, |
729 | 17011,17021,17027,17029,17033,17041,17047,17053, |
730 | 17077,17093,17099,17107,17117,17123,17137,17159, |
731 | 17167,17183,17189,17191,17203,17207,17209,17231, |
732 | 17239,17257,17291,17293,17299,17317,17321,17327, |
733 | 17333,17341,17351,17359,17377,17383,17387,17389, |
734 | 17393,17401,17417,17419,17431,17443,17449,17467, |
735 | 17471,17477,17483,17489,17491,17497,17509,17519, |
736 | 17539,17551,17569,17573,17579,17581,17597,17599, |
737 | 17609,17623,17627,17657,17659,17669,17681,17683, |
738 | 17707,17713,17729,17737,17747,17749,17761,17783, |
739 | 17789,17791,17807,17827,17837,17839,17851,17863 |
740 | }; |
741 | #endif |
742 | #endif |
#ifndef _CRYPTDATAECC_H_
#define _CRYPTDATAECC_H_
Structure for the curve parameters. This is an analog to the TPMS_ALGORITHM_DETAIL_ECC
typedef struct {
const TPM2B *p; // a prime number
const TPM2B *a; // linear coefficient
const TPM2B *b; // constant term
const TPM2B *x; // generator x coordinate
const TPM2B *y; // generator y coordinate
const TPM2B *n; // the order of the curve
const TPM2B *h; // cofactor
} ECC_CURVE_DATA;
typedef struct 13 {
TPM_ECC_CURVE curveId;
UINT16 keySizeBits;
TPMT_KDF_SCHEME kdf;
TPMT_ECC_SCHEME sign;
const ECC_CURVE_DATA *curveData; // the address of the curve data
} ECC_CURVE;
extern const ECC_CURVE_DATA SM2_P256;
extern const ECC_CURVE_DATA NIST_P256;
extern const ECC_CURVE_DATA BN_P256;
extern const ECC_CURVE eccCurves[];
extern const UINT16 ECC_CURVE_COUNT;
25 #endif
Defines for the sizes of ECC parameters
#include "TPMB.h"
TPM2B_BYTE_VALUE(1);
TPM2B_BYTE_VALUE(16);
TPM2B_BYTE_VALUE(2);
TPM2B_BYTE_VALUE(24);
TPM2B_BYTE_VALUE(28);
TPM2B_BYTE_VALUE(32);
TPM2B_BYTE_VALUE(4);
TPM2B_BYTE_VALUE(48);
TPM2B_BYTE_VALUE(64);
TPM2B_BYTE_VALUE(66);
TPM2B_BYTE_VALUE(8);
TPM2B_BYTE_VALUE(80);
#if defined ECC_NIST_P192 && ECC_NIST_P192 == YES
const TPM2B_24_BYTE_VALUE NIST_P192_p = {24,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
const TPM2B_24_BYTE_VALUE NIST_P192_a = {24,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC}};
const TPM2B_24_BYTE_VALUE NIST_P192_b = {24,
24 {0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C, 0x80, 0xE7,
25 0x0F, 0xA7, 0xE9, 0xAB, 0x72, 0x24, 0x30, 0x49,
26 0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46, 0xB9, 0xB1}};
27 const TPM2B_24_BYTE_VALUE NIST_P192_gX = {24,
28 {0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6,
29 0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00,
30 0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12}};
31 const TPM2B_24_BYTE_VALUE NIST_P192_gY = {24,
32 {0x07, 0x19, 0x2B, 0x95, 0xFFC, 0x8D, 0xA7, 0x86,
33 0x31, 0x01, 0x1ED, 0x6B, 0x24, 0xCD, 0xD5, 0x73,
34 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11}};
const TPM2B_24_BYTE_VALUE NIST_P192_n = {24,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 37 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36, 38 0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31}};
const TPM2B_1_BYTE_VALUE NIST_P192_h = {1,{1}};
const ECC_CURVE_DATA NIST_P192 = {&NIST_P192_p.b, &NIST_P192_a.b, &NIST_P192_b.b, 41 &NIST_P192_gX.b, &NIST_P192_gY.b, &NIST_P192_n.b,
42 &NIST_P192_h.b};
#endif // ECC_NIST_P192
#if defined ECC_NIST_P224 && ECC_NIST_P224 == YES
const TPM2B_28_BYTE_VALUE NIST_P224_p = {28,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x01}};
const TPM2B_28_BYTE_VALUE NIST_P224_a = {28,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE}};
const TPM2B_28_BYTE_VALUE NIST_P224_b = {28,
56 {0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB,
57 0xF5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xB0, 0xB7,
58 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43,
59 0x23, 0x55, 0xFF, 0xB4}};
60 const TPM2B_28_BYTE_VALUE NIST_P224_gX = {28,
61 {0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F,
62 0x32, 0x13, 0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3,
63 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6,
64 0x11, 0x5C, 0x1D, 0x21}};
65 const TPM2B_28_BYTE_VALUE NIST_P224_gY = {28,
66 {0xBD, 0x37, 0x63, 0x88, 0xB5, 0xF7, 0x23, 0xFB,
67 0x4C, 0x22, 0xDF, 0xE6, 0xCD, 0x43, 0x75, 0xA0,
68 0x5A, 0x07, 0x47, 0x64, 0x44, 0xD5, 0x81, 0x99,
69 0x85, 0x00, 0x7E, 0x34}};
const TPM2B_28_BYTE_VALUE NIST_P224_n = {28,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x16, 0xA2,
73 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45,
74 0x5C, 0x5C, 0x2A, 0x3D}};
const TPM2B_1_BYTE_VALUE NIST_P224_h = {1,{1}};
const ECC_CURVE_DATA NIST_P224 = {&NIST_P224_p.b, &NIST_P224_a.b, &NIST_P224_b.b, 77 &NIST_P224_gX.b, &NIST_P224_gY.b, &NIST_P224_n.b,
78 &NIST_P224_h.b};
#endif // ECC_NIST_P224
#if defined ECC_NIST_P256 && ECC_NIST_P256 == YES
const TPM2B_32_BYTE_VALUE NIST_P256_p = {32,
82 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
const TPM2B_32_BYTE_VALUE NIST_P256_a = {32,
87 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC}};
const TPM2B_32_BYTE_VALUE NIST_P256_b = {32,
92 {0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7,
93 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC,
94 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
95 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B}};
96 const TPM2B_32_BYTE_VALUE NIST_P256_gX = {32,
97 {0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
98 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
99 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
100 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96}};
101 const TPM2B_32_BYTE_VALUE NIST_P256_gY = {32,
102 {0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
103 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
104 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
105 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5}};
106 const TPM2B_32_BYTE_VALUE NIST_P256_n = {32,
107 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
108 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 109 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 110 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51}};
const TPM2B_1_BYTE_VALUE NIST_P256_h = {1,{1}};
const ECC_CURVE_DATA NIST_P256 = {&NIST_P256_p.b, &NIST_P256_a.b, &NIST_P256_b.b,
113 &NIST_P256_gX.b, &NIST_P256_gY.b, &NIST_P256_n.b,
114 &NIST_P256_h.b};
#endif // ECC_NIST_P256
#if defined ECC_NIST_P384 && ECC_NIST_P384 == YES
const TPM2B_48_BYTE_VALUE NIST_P384_p = {48,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 122 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 123 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}};
const TPM2B_48_BYTE_VALUE NIST_P384_a = {48,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
128 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, |
129 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
130 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC}}; |
131 | const TPM2B_48_BYTE_VALUE NIST_P384_b = {48, |
132 | {0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, |
133 | 0x98, 0x8E, 0x05, 0x6B, 0xE3, 0xF8, 0x2D, 0x19, |
134 | 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, |
135 | 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, |
136 | 0xC6, 0x56, 0x39, 0x8D, 0x8A, 0x2E, 0xD1, 0x9D, |
137 | 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF}}; |
138 | const TPM2B_48_BYTE_VALUE NIST_P384_gX = {48, |
139 | {0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, |
140 | 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74, |
141 | 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, |
142 | 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, |
143 | 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, |
144 | 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7}}; |
145 | const TPM2B_48_BYTE_VALUE NIST_P384_gY = {48, |
146 | {0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, |
147 | 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29, |
148 | 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, |
149 | 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0, |
150 | 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, |
151 | 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F}}; |
152 | const TPM2B_48_BYTE_VALUE NIST_P384_n = {48, |
153 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
154 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
155 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
156 | 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, |
157 | 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, |
158 | 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73}}; |
159 | const TPM2B_1_BYTE_VALUE NIST_P384_h = {1,{1}}; |
160 | const ECC_CURVE_DATA NIST_P384 = {&NIST_P384_p.b, &NIST_P384_a.b, &NIST_P384_b.b, |
161 | &NIST_P384_gX.b, &NIST_P384_gY.b, &NIST_P384_n.b, |
162 | &NIST_P384_h.b}; |
163 | #endif // ECC_NIST_P384 |
164 | #if defined ECC_NIST_P521 && ECC_NIST_P521 == YES |
165 | const TPM2B_66_BYTE_VALUE NIST_P521_p = {66, |
166 | {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
167 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
168 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
169 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
170 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
171 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
172 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
173 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
174 | 0xFF, 0xFF}}; |
175 | const TPM2B_66_BYTE_VALUE NIST_P521_a = {66, |
176 | {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
177 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
178 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
179 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
180 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
181 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
182 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
183 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
184 | 0xFF, 0xFC}}; |
185 | const TPM2B_66_BYTE_VALUE NIST_P521_b = {66, |
186 | {0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, |
187 | 0x9A, 0x1F, 0x92, 0x9A, 0x21, 0xA0, 0xB6, 0x85, |
188 | 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, |
189 | 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, |
190 | 0x09, 0xE1, 0x56, 0x19, 0x39, 0x51, 0xEC, 0x7E, |
191 | 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1, |
192 | 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, |
193 | 0x34, 0xF1, 0xEF, 0x45, 0x1F, 0xD4, 0x6B, 0x50, |
194 0x3F, 0x00}};
195 const TPM2B_66_BYTE_VALUE NIST_P521_gX = {66,
196 {0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04,
197 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95,
198 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F,
199 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D,
200 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7,
201 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
202 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A,
203 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5,
204 0xBD, 0x66}};
205 const TPM2B_66_BYTE_VALUE NIST_P521_gY = {66,
206 {0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B,
207 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D,
208 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B,
209 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E,
210 0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4,
211 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD,
212 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72,
213 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1,
214 0x66, 0x50}};
const TPM2B_66_BYTE_VALUE NIST_P521_n = {66,
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 220 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 221 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, 222 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 223 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38, 224 0x64, 0x09}};
const TPM2B_1_BYTE_VALUE NIST_P521_h = {1,{1}};
const ECC_CURVE_DATA NIST_P521 = {&NIST_P521_p.b, &NIST_P521_a.b, &NIST_P521_b.b,
227 &NIST_P521_gX.b, &NIST_P521_gY.b, &NIST_P521_n.b,
228 &NIST_P521_h.b};
#endif // ECC_NIST_P521
#if defined ECC_BN_P256 && ECC_BN_P256 == YES
const TPM2B_32_BYTE_VALUE BN_P256_p = {32,
{0xFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFC, 0XF0, 0XCD, 233 0X46, 0XE5, 0XF2, 0X5E, 0XEE, 0X71, 0XA4, 0X9F, 234 0X0C, 0XDC, 0X65, 0XFB, 0X12, 0X98, 0X0A, 0X82, 235 0XD3, 0X29, 0X2D, 0XDB, 0XAE, 0XD3, 0X30, 0X13}};
const TPM2B_1_BYTE_VALUE BN_P256_a = {1,{0}};
const TPM2B_1_BYTE_VALUE BN_P256_b = {1,{3}};
const TPM2B_1_BYTE_VALUE BN_P256_gX = {1,{1}};
const TPM2B_1_BYTE_VALUE BN_P256_gY = {1,{2}};;
const TPM2B_32_BYTE_VALUE BN_P256_n = {32,
{0xFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFC, 0XF0, 0XCD, 242 0X46, 0XE5, 0XF2, 0X5E, 0XEE, 0X71, 0XA4, 0X9E, 243 0X0C, 0XDC, 0X65, 0XFB, 0X12, 0X99, 0X92, 0X1A, 244 0XF6, 0X2D, 0X53, 0X6C, 0XD1, 0X0B, 0X50, 0X0D}};
const TPM2B_1_BYTE_VALUE BN_P256_h = {1,{1}};
const ECC_CURVE_DATA BN_P256 = {&BN_P256_p.b, &BN_P256_a.b, &BN_P256_b.b,
247 &BN_P256_gX.b, &BN_P256_gY.b, &BN_P256_n.b,
248 &BN_P256_h.b};
#endif // ECC_BN_P256
#if defined ECC_BN_P638 && ECC_BN_P638 == YES
const TPM2B_80_BYTE_VALUE BN_P638_p = {80,
252 {0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D,
253 0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3,
254 0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E,
255 0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F,
256 0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55,
257 0xC0, 0x00, 0x86, 0x52, 0x00, 0x21, 0xE5, 0x5B,
258 0xFF, 0xFF, 0xF5, 0x1F, 0xFF, 0xF4, 0xEB, 0x80,
259 0x00, 0x00, 0x00, 0x4C, 0x80, 0x01, 0x5A, 0xCD,
260 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xE0, 261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67}};
262 const TPM2B_1_BYTE_VALUE BN_P638_a = {1,{0}};
263 const TPM2B_2_BYTE_VALUE BN_P638_b = {2,{0x01,0x01}};
264 const TPM2B_80_BYTE_VALUE BN_P638_gX = {80,
265 {0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D,
266 0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3,
267 0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E,
268 0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F,
269 0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55,
270 0xC0, 0x00, 0x86, 0x52, 0x00, 0x21, 0xE5, 0x5B,
271 0xFF, 0xFF, 0xF5, 0x1F, 0xFF, 0xF4, 0xEB, 0x80,
272 0x00, 0x00, 0x00, 0x4C, 0x80, 0x01, 0x5A, 0xCD,
273 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xE0, 274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66}};
const TPM2B_1_BYTE_VALUE BN_P638_gY = {1,{0x10}};
const TPM2B_80_BYTE_VALUE BN_P638_n = {80,
277 {0x23, 0xFF, 0xFF, 0xFD, 0xC0, 0x00, 0x00, 0x0D,
278 0x7F, 0xFF, 0xFF, 0xB8, 0x00, 0x00, 0x01, 0xD3,
279 0xFF, 0xFF, 0xF9, 0x42, 0xD0, 0x00, 0x16, 0x5E,
280 0x3F, 0xFF, 0x94, 0x87, 0x00, 0x00, 0xD5, 0x2F,
281 0xFF, 0xFD, 0xD0, 0xE0, 0x00, 0x08, 0xDE, 0x55,
282 0x60, 0x00, 0x86, 0x55, 0x00, 0x21, 0xE5, 0x55,
283 0xFF, 0xFF, 0xF5, 0x4F, 0xFF, 0xF4, 0xEA, 0xC0, 284 0x00, 0x00, 0x00, 0x49, 0x80, 0x01, 0x54, 0xD9,
285 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xA0, 286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61}};
const TPM2B_1_BYTE_VALUE BN_P638_h = {1,{1}};
const ECC_CURVE_DATA BN_P638 = {&BN_P638_p.b, &BN_P638_a.b, &BN_P638_b.b,
289 &BN_P638_gX.b, &BN_P638_gY.b, &BN_P638_n.b,
290 &BN_P638_h.b};
#endif // ECC_BN_P638
#if defined ECC_SM2_P256 && ECC_SM2_P256 == YES
const TPM2B_32_BYTE_VALUE SM2_P256_p = {32,
{0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 296 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
const TPM2B_32_BYTE_VALUE SM2_P256_a = {32,
{0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 301 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC}};
const TPM2B_32_BYTE_VALUE SM2_P256_b = {32,
304 {0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34,
305 0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7,
306 0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92,
307 0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93}};
308 const TPM2B_32_BYTE_VALUE SM2_P256_gX = {32,
309 {0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19,
310 0x5F, 0x99, 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94,
311 0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1,
312 0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7}};
313 const TPM2B_32_BYTE_VALUE SM2_P256_gY = {32,
314 {0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C,
315 0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53,
316 0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40,
317 0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0}};
const TPM2B_32_BYTE_VALUE SM2_P256_n = {32,
{0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 321 0x72, 0x03, 0xDF, 0x6B, 0x21, 0xC6, 0x05, 0x2B, 322 0x53, 0xBB, 0xF4, 0x09, 0x39, 0xD5, 0x41, 0x23}};
323 const TPM2B_1_BYTE_VALUE SM2_P256_h = {1,{1}};
324 const ECC_CURVE_DATA SM2_P256 = {&SM2_P256_p.b, &SM2_P256_a.b, &SM2_P256_b.b, 325 &SM2_P256_gX.b, &SM2_P256_gY.b, &SM2_P256_n.b,
326 &SM2_P256_h.b};
#endif // ECC_SM2_P256
#define comma
const ECC_CURVE eccCurves[] = {
330 | #if defined ECC_NIST_P192 && ECC_NIST_P192 == | YES |
331 | comma | |
332 | {TPM_ECC_NIST_P192, | |
333 | 192, | |
334 | {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SHA256}, | |
335 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
336 | &NIST_P192} | |
337 | # undef comma | |
338 | # define comma , | |
339 | #endif // ECC_NIST_P192 | |
340 | #if defined ECC_NIST_P224 && ECC_NIST_P224 == | YES |
341 | comma | |
342 | {TPM_ECC_NIST_P224, | |
343 | 224, | |
344 | {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SHA256}, | |
345 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
346 | &NIST_P224} | |
347 | # undef comma | |
348 | # define comma , | |
349 | #endif // ECC_NIST_P224 | |
350 | #if defined ECC_NIST_P256 && ECC_NIST_P256 == | YES |
351 | comma | |
352 | {TPM_ECC_NIST_P256, | |
353 | 256, | |
354 | {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SHA256}, | |
355 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
356 | &NIST_P256} | |
357 | # undef comma | |
358 | # define comma , | |
359 | #endif // ECC_NIST_P256 | |
360 | #if defined ECC_NIST_P384 && ECC_NIST_P384 == | YES |
361 | comma | |
362 | {TPM_ECC_NIST_P384, | |
363 | 384, | |
364 | {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SHA384}, | |
365 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
366 | &NIST_P384} | |
367 | # undef comma | |
368 | # define comma , | |
369 | #endif // ECC_NIST_P384 | |
370 | #if defined ECC_NIST_P521 && ECC_NIST_P521 == | YES |
371 | comma | |
372 | {TPM_ECC_NIST_P521, | |
373 | 521, | |
374 | {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SHA512}, | |
375 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
376 | &NIST_P521} | |
377 | # undef comma | |
378 | # define comma , | |
379 | #endif // ECC_NIST_P521 | |
380 | #if defined ECC_BN_P256 && ECC_BN_P256 == YES | |
381 | comma | |
382 | {TPM_ECC_BN_P256, | |
383 | 256, | |
384 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
385 | {TPM_ALG_NULL,TPM_ALG_NULL}, | |
386 | &BN_P256} | |
387 | # undef comma | |
388 | # define comma , | |
389 | #endif // ECC_BN_P256 | |
390 | #if defined ECC_BN_P638 && ECC_BN_P638 == YES | |
391 | comma |
392 {TPM_ECC_BN_P638,
393 638,
{TPM_ALG_NULL,TPM_ALG_NULL},
{TPM_ALG_NULL,TPM_ALG_NULL}, 396 &BN_P638}
# undef comma
# define comma ,
#endif // ECC_BN_P638
#if defined ECC_SM2_P256 && ECC_SM2_P256 == YES
comma
{TPM_ECC_SM2_P256,
403 256,
404 {TPM_ALG_KDF1_SP800_56A,TPM_ALG_SM3_256},
405 {TPM_ALG_NULL,TPM_ALG_NULL}, 406 &SM2_P256}
407 # undef comma
408 # define comma ,
409 #endif // ECC_SM2_P256 410 };
411 const UINT16 ECC_CURVE_COUNT = sizeof(eccCurves) / sizeof(ECC_CURVE);
Need to include OsslCryptEngine.h to determine if ECC is defined for this Implementation
#include "OsslCryptoEngine.h"
#ifdef TPM_ALG_ECC
#include "CpriDataEcc.h"
#include "CpriDataEcc.c"
This function is called at TPM Startup to initialize the crypto units.
In this implementation, no initialization is performed at startup but a future version may initialize the self- test functions here.
LIB_EXPORT BOOL
_cpri EccStartup(
void
8 )
9 {
10 return TRUE; 11 }
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.
LIB_EXPORT TPM_ECC_CURVE
_cpri GetCurveIdByIndex(
UINT16 i
15 )
16 {
if(i >= ECC_CURVE_COUNT)
return TPM_ECC_NONE;
return eccCurves[i].curveId; 20 }
LIB_EXPORT UINT32
_cpri EccGetCurveCount(
void
24 )
25 {
26 return ECC_CURVE_COUNT; 27 }
_cpri__EccGetParametersByCurveId()
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.
Return Value | Meaning |
NULL | curve with the indicated TPM_ECC_CURVE value is not implemented |
non-NULL | pointer to the curve data |
LIB_EXPORT const ECC_CURVE *
_cpri EccGetParametersByCurveId(
TPM_ECC_CURVE curveId // IN: the curveID 31 )
32 {
int i;
for(i = 0; i < ECC_CURVE_COUNT; i++) 35 {
if(eccCurves[i].curveId == curveId)
return &eccCurves[i]; 38 }
39 FAIL(FATAL_ERROR_INTERNAL); 40 }
static const ECC_CURVE_DATA *
GetCurveData(
TPM_ECC_CURVE curveId // IN: the curveID 44 )
45 {
const ECC_CURVE *curve = _cpri EccGetParametersByCurveId(curveId);
return curve->curveData; 48 }
This function makes a TPMS_ECC_POINT from a BIGNUM EC_POINT.
static BOOL
Point2B(
EC_GROUP *group, // IN: group for the point
TPMS_ECC_POINT *p, // OUT: receives the converted point
EC_POINT *ecP, // IN: the point to convert
INT16 size, // IN: size of the coordinates
BN_CTX *context // IN: working context 56 )
57 {
BIGNUM *bnX;
BIGNUM *bnY; 60
BN_CTX_start(context);
bnX = BN_CTX_get(context);
bnY = BN_CTX_get(context); 64
65 if( bnY == NULL 66
// Get the coordinate values
|| EC_POINT_get_affine_coordinates_GFp(group, ecP, bnX, bnY, context) != 1 69
// Convert x
|| (!BnTo2B(&p->x.b, bnX, size)) 72
// Convert y
|| (!BnTo2B(&p->y.b, bnY, size))
75 )
76 FAIL(FATAL_ERROR_INTERNAL); 77
BN_CTX_end(context);
return TRUE;
80 }
This function initializes the OpenSSL() group definition structure This function is only used within this file.
It is a fatal error if groupContext is not provided.
Return Value | Meaning |
NULL | the TPM_ECC_CURVE is not valid |
non-NULL | points to a structure in groupContext static EC_GROUP * |
static EC_GROUP *
EccCurveInit(
TPM_ECC_CURVE curveId, // IN: the ID of the curve
BN_CTX *groupContext // IN: the context in which the group is to be
// created
86 )
87 {
const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
EC_GROUP *group = NULL;
EC_POINT *P = NULL;
BN_CTX *context;
BIGNUM *bnP;
BIGNUM *bnA;
BIGNUM *bnB;
BIGNUM *bnX;
BIGNUM *bnY;
BIGNUM *bnN;
BIGNUM *bnH;
int ok = FALSE; 100
// Context must be provided and curve selector must be valid
pAssert(groupContext != NULL && curveData != NULL); 103
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 107
BN_CTX_start(context);
bnP = BN_CTX_get(context);
bnA = BN_CTX_get(context);
bnB = BN_CTX_get(context);
bnX = BN_CTX_get(context);
bnY = BN_CTX_get(context);
bnN = BN_CTX_get(context);
bnH = BN_CTX_get(context); 116
if (bnH == NULL)
goto Cleanup; 119
120 // Convert the number formats 121
BnFrom2B(bnP, curveData->p);
BnFrom2B(bnA, curveData->a);
BnFrom2B(bnB, curveData->b);
BnFrom2B(bnX, curveData->x);
BnFrom2B(bnY, curveData->y);
BnFrom2B(bnN, curveData->n);
BnFrom2B(bnH, curveData->h); 129
// initialize EC group, associate a generator point and initialize the point
// from the parameter data
ok = ( (group = EC_GROUP_new_curve_GFp(bnP, bnA, bnB, groupContext)) != NULL
&& (P = EC_POINT_new(group)) != NULL
&& EC_POINT_set_affine_coordinates_GFp(group, P, bnX, bnY, groupContext)
&& EC_GROUP_set_generator(group, P, bnN, bnH)
136 );
Cleanup:
if (!ok && group != NULL)
139 {
EC_GROUP_free(group);
group = NULL;
142 }
if(P != NULL)
EC_POINT_free(P);
BN_CTX_end(context);
BN_CTX_free(context);
return group;
148 }
This function sets the coordinates of an existing BN Point from a TPMS_ECC_POINT.
149 | static EC_POINT * |
150 | PointFrom2B( |
151 | EC_GROUP *group, // IN: the group for the point |
152 | EC_POINT *ecP, // IN: an existing BN point in the group |
153 | TPMS_ECC_POINT *p, // IN: the 2B coordinates of the point |
154 | BN_CTX *context // IN: the BIGNUM context |
155 | ) |
156 | { |
157 | BIGNUM *bnX; |
158 | BIGNUM *bnY; |
159 | |
160 | // If the point is not allocated then just return a NULL |
161 | if(ecP == NULL) |
162 | return NULL; |
163 | |
164 | BN_CTX_start(context); |
165 | bnX = BN_CTX_get(context); |
166 | bnY = BN_CTX_get(context); |
167 | if( // Set the coordinates of the point |
168 | bnY == NULL |
169 | || BN_bin2bn(p->x.t.buffer, p->x.t.size, bnX) == NULL |
170 | || BN_bin2bn(p->y.t.buffer, p->y.t.size, bnY) == NULL |
171 | || !EC_POINT_set_affine_coordinates_GFp(group, ecP, bnX, bnY, context) |
172 | ) |
173 | FAIL(FATAL_ERROR_INTERNAL); |
174 | |
175 | BN_CTX_end(context); |
176 | return ecP; |
177 | } |
This function allocates a point in the provided group and initializes it with the values in a TPMS_ECC_POINT.
static EC_POINT *
EccInitPoint2B(
EC_GROUP *group, // IN: group for the point
TPMS_ECC_POINT *p, // IN: the coordinates for the point
182 | BN_CTX *context // IN: the BIGNUM context | |
183 | ) | |
184 | { | |
185 | EC_POINT *ecP; | |
186 | ||
187 | BN_CTX_start(context); | |
188 | ecP = EC_POINT_new(group); | |
189 | ||
190 | if(PointFrom2B(group, ecP, p, context) == NULL) | |
191 | FAIL(FATAL_ERROR_INTERNAL); | |
192 | ||
193 | BN_CTX_end(context); | |
194 | return ecP; | |
195 | } |
This function does a point multiply and checks for the result being the point at infinity. Q = ([A]G + [B]P)
Return Value | Meaning |
CRYPT_NO_RESULT | point is at infinity |
CRYPT_SUCCESS | point not at infinity |
static CRYPT_RESULT
PointMul(
EC_GROUP *group, // IN: group curve
EC_POINT *ecpQ, // OUT: result
BIGNUM *bnA, // IN: scalar for [A]G
EC_POINT *ecpP, // IN: point for [B]P
BIGNUM *bnB, // IN: scalar for [B]P
BN_CTX *context // IN: working context
204 )
205 {
if(EC_POINT_mul(group, ecpQ, bnA, ecpP, bnB, context) != 1)
FAIL(FATAL_ERROR_INTERNAL);
if(EC_POINT_is_at_infinity(group, ecpQ))
return CRYPT_NO_RESULT;
return CRYPT_SUCCESS;
211 }
This function gets a random value (d) to use as a private ECC key and then qualifies the key so that it is between 0 < d < n.
It is a fatal error if dOut or pIn is not provided or if the size of pIn is larger than MAX_ECC_KEY_BYTES (the largest buffer size of a TPM2B_ECC_PARAMETER)
static void
GetRandomPrivate(
TPM2B_ECC_PARAMETER *dOut, // OUT: the qualified random value
const TPM2B *pIn // IN: the maximum value for the key
216 )
217 {
int i;
BYTE *pb; 220
221 pAssert(pIn != NULL && dOut != NULL && pIn->size <= MAX_ECC_KEY_BYTES); 222
// Set the size of the output
dOut->t.size = pIn->size;
// Get some random bits
while(TRUE)
227 {
_cpri GenerateRandom(dOut->t.size, dOut->t.buffer);
// See if the d < n
if(memcmp(dOut->t.buffer, pIn->buffer, pIn->size) < 0)
231 {
// dOut < n so make sure that 0 < dOut
for(pb = dOut->t.buffer, i = dOut->t.size; i > 0; i--)
234 {
235 if(*pb++ != 0)
236 return;
237 }
238 }
239 }
240 }
Function does modular reduction of TPM2B values.
static CRYPT_RESULT
Mod2B(
TPM2B *x, // IN/OUT: value to reduce
const TPM2B *n // IN: mod
245 )
246 {
int compare;
compare = _math uComp(x->size, x->buffer, n->size, n->buffer);
if(compare < 0)
// if x < n, then mod is x
return CRYPT_SUCCESS;
if(compare == 0)
253 {
// if x == n then mod is 0
x->size = 0;
256 x->buffer[0] = 0;
257 return CRYPT_SUCCESS;
258 }
259 return _math Div(x, n, NULL, x);
260 }
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 CRYPT_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.
Return Value | Meaning |
CRYPT_SUCCESS | point multiplication succeeded |
CRYPT_POINT | the point Qin is not on the curve |
CRYPT_NO_RESULT | the product point is at infinity |
LIB_EXPORT CRYPT_RESULT
_cpri EccPointMultiply(
TPMS_ECC_POINT *Rout, // OUT: the product point R
TPM_ECC_CURVE curveId, // IN: the curve to use
TPM2B_ECC_PARAMETER *dIn, // IN: value to multiply against the
// curve generator
TPMS_ECC_POINT *Qin, // IN: point Q
TPM2B_ECC_PARAMETER *uIn // IN: scalar value for the multiplier
// of Q
270 )
271 {
BN_CTX *context;
BIGNUM *bnD;
BIGNUM *bnU;
EC_GROUP *group;
EC_POINT *R = NULL;
EC_POINT *Q = NULL;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 279
// Validate that the required parameters are provided.
pAssert((dIn != NULL || uIn != NULL) && (Qin != NULL || dIn != NULL)); 282
// If a point is provided for the multiply, make sure that it is on the curve
if(Qin != NULL && !_cpri EccIsPointOnCurve(curveId, Qin))
return CRYPT_POINT; 286
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 290
BN_CTX_start(context);
bnU = BN_CTX_get(context);
bnD = BN_CTX_get(context);
group = EccCurveInit(curveId, context); 295
// There should be no path for getting a bad curve ID into this function.
pAssert(group != NULL); 298
// check allocations should have worked and allocate R
if( bnD == NULL
|| (R = EC_POINT_new(group)) == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 303
// If Qin is present, create the point
if(Qin != NULL)
306 {
// Assume the size variables do not overflow. This should not happen in
// the contexts in which this function will be called.
assert2Bsize(Qin->x.t);
assert2Bsize(Qin->x.t);
Q = EccInitPoint2B(group, Qin, context); 312
313 }
314 if(dIn != NULL)
315 {
// Assume the size variables do not overflow, which should not happen in
// the contexts that this function will be called.
assert2Bsize(dIn->t);
319 | BnFrom2B(bnD, &dIn->b); | |
320 | } | |
321 | else | |
322 | bnD = NULL; | |
323 | ||
324 | // If uIn is specified, initialize its BIGNUM | |
325 | if(uIn != NULL) | |
326 | { | |
327 | // Assume the size variables do not overflow, which should not happen in | |
328 | // the contexts that this function will be called. | |
329 | assert2Bsize(uIn->t); | |
330 | BnFrom2B(bnU, &uIn->b); | |
331 | } | |
332 | // If uIn is not specified but Q is, then we are going to | |
333 | // do R = [d]Q | |
334 | else if(Qin != NULL) | |
335 | { | |
336 | bnU = bnD; | |
337 | bnD = NULL; | |
338 | } | |
339 | // If neither Q nor u is specified, then null this pointer | |
340 | else | |
341 | bnU = NULL; | |
342 | ||
343 | // Use the generator of the curve | |
344 | if((retVal = PointMul(group, R, bnD, Q, bnU, context)) == CRYPT_SUCCESS) | |
345 | Point2B(group, Rout, R, (INT16) BN_num_bytes(&group->field), context); | |
346 | ||
347 | if (Q) | |
348 | EC_POINT_free(Q); | |
349 | if(R) | |
350 | EC_POINT_free(R); | |
351 | if(group) | |
352 | EC_GROUP_free(group); | |
353 | BN_CTX_end(context); | |
354 | BN_CTX_free(context); | |
355 | return retVal; | |
356 | } |
Initialize the size values of a point
static void
ClearPoint2B(
TPMS_ECC_POINT *p // IN: the point
360 )
361 {
if(p != NULL) {
p->x.t.size = 0;
p->y.t.size = 0;
365 }
366 }
#if defined TPM_ALG_ECDAA || defined TPM_ALG_SM2 //%
This function performs the point multiply operations required by TPM2_Commit().
If B or M is provided, they must be on the curve defined by curveId. This routine does not check that they are on the curve and results are unpredictable if they are not.
It is a fatal error if r or d is NULL. If B is not NULL, then it is a fatal error if K and L are both NULL. If M is not NULL, then it is a fatal error if E is NULL.
Return Value | Meaning |
CRYPT_SUCCESS | computations completed normally |
CRYPT_NO_RESULT | if K, L or E was computed to be the point at infinity |
CRYPT_CANCEL | a cancel indication was asserted during this function |
LIB_EXPORT CRYPT_RESULT
_cpri EccCommitCompute(
TPMS_ECC_POINT *K, // OUT: [d]B or [r]Q
TPMS_ECC_POINT *L, // OUT: [r]B
TPMS_ECC_POINT *E, // OUT: [r]M
TPM_ECC_CURVE curveId, // IN: the curve for the computations
TPMS_ECC_POINT *M, // IN: M (optional)
TPMS_ECC_POINT *B, // IN: B (optional)
TPM2B_ECC_PARAMETER *d, // IN: d (required)
TPM2B_ECC_PARAMETER *r // IN: the computed r value (required)
378 )
379 {
BN_CTX *context;
BIGNUM *bnX, *bnY, *bnR, *bnD;
EC_GROUP *group;
EC_POINT *pK = NULL, *pL = NULL, *pE = NULL, *pM = NULL, *pB = NULL;
UINT16 keySizeInBytes;
CRYPT_RESULT retVal = CRYPT_SUCCESS; 386
// Validate that the required parameters are provided.
// Note: E has to be provided if computing E := [r]Q or E := [r]M. Will do
// E := [r]Q if both M and B are NULL.
pAssert( r != NULL && (K != NULL || B == NULL) && (L != NULL || B == NULL) 391 || (E != NULL || (M == NULL && B != NULL)));
392
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnR = BN_CTX_get(context);
bnD = BN_CTX_get(context);
bnX = BN_CTX_get(context);
bnY = BN_CTX_get(context);
if(bnY == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 403
404 // Initialize the output points in case they are not computed
405 ClearPoint2B(K);
406 ClearPoint2B(L);
407 ClearPoint2B(E); 408
409 if((group = EccCurveInit(curveId, context)) == NULL)
410 {
411 retVal = CRYPT_PARAMETER;
412 goto Cleanup2;
413 }
414 keySizeInBytes = (UINT16) BN_num_bytes(&group->field); 415
416 // Sizes of the r and d parameters may not be zero
417 pAssert(((int) r->t.size > 0) && ((int) d->t.size > 0)); 418
419 // Convert scalars to BIGNUM
420 BnFrom2B(bnR, &r->b);
421 BnFrom2B(bnD, &d->b); 422
423 // If B is provided, compute K=[d]B and L=[r]B
424 if(B != NULL)
425 {
// Allocate the points to receive the value
if( (pK = EC_POINT_new(group)) == NULL
|| (pL = EC_POINT_new(group)) == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
// need to compute K = [d]B
// Allocate and initialize BIGNUM version of B
pB = EccInitPoint2B(group, B, context); 433
434 // do the math for K = [d]B
435 if((retVal = PointMul(group, pK, NULL, pB, bnD, context)) != CRYPT_SUCCESS)
436 goto Cleanup; 437
438 // Convert BN K to TPM2B K
439 Point2B(group, K, pK, (INT16)keySizeInBytes, context); 440
441 // compute L= [r]B after checking for cancel
442 if(_plat IsCanceled())
443 {
444 retVal = CRYPT_CANCEL;
445 goto Cleanup;
446 }
447 // compute L = [r]B
448 if((retVal = PointMul(group, pL, NULL, pB, bnR, context)) != CRYPT_SUCCESS)
449 goto Cleanup; 450
451 // Convert BN L to TPM2B L
452 Point2B(group, L, pL, (INT16)keySizeInBytes, context);
453 }
454 if(M != NULL || B == NULL)
455 {
456 // if this is the third point multiply, check for cancel first
457 if(B != NULL && _plat IsCanceled())
458 {
459 retVal = CRYPT_CANCEL;
460 goto Cleanup;
461 }
462
463 // Allocate E
464 if((pE = EC_POINT_new(group)) == NULL)
465 FAIL(FATAL_ERROR_ALLOCATION); 466
467 // Create BIGNUM version of M unless M is NULL
468 if(M != NULL)
469 {
470 // M provided so initialize a BIGNUM M and compute E = [r]M
471 pM = EccInitPoint2B(group, M, context);
472 retVal = PointMul(group, pE, NULL, pM, bnR, context);
473 }
474 else
475 // compute E = [r]G (this is only done if M and B are both NULL
476 retVal = PointMul(group, pE, bnR, NULL, NULL, context); 477
478 if(retVal == CRYPT_SUCCESS)
479 // Convert E to 2B format
480 Point2B(group, E, pE, (INT16)keySizeInBytes, context);
481 }
Cleanup:
EC_GROUP_free(group);
if(pK != NULL) EC_POINT_free(pK);
if(pL != NULL) EC_POINT_free(pL);
if(pE != NULL) EC_POINT_free(pE);
if(pM != NULL) EC_POINT_free(pM);
if(pB != NULL) EC_POINT_free(pB);
Cleanup2:
BN_CTX_end(context);
BN_CTX_free(context);
return retVal;
493 }
494 #endif //%
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).
Return Value | Meaning |
TRUE | point is on curve |
FALSE | point is not on curve or curve is not supported |
495 LIB_EXPORT BOOL
496 _cpri EccIsPointOnCurve(
497 TPM_ECC_CURVE curveId, // IN: the curve selector
498 TPMS_ECC_POINT *Q // IN: the point.
499 )
500 {
BN_CTX *context;
BIGNUM *bnX;
BIGNUM *bnY;
BIGNUM *bnA;
BIGNUM *bnB;
BIGNUM *bnP;
BIGNUM *bn3;
const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
BOOL retVal; 510
511 pAssert(Q != NULL && curveData != NULL); 512
if((context = BN_CTX_new()) == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnX = BN_CTX_get(context);
bnY = BN_CTX_get(context);
bnA = BN_CTX_get(context);
bnB = BN_CTX_get(context);
bn3 = BN_CTX_get(context);
bnP = BN_CTX_get(context);
if(bnP == NULL)
FAIL(FATAL_ERROR_ALLOCATION); 524
// Convert values
if ( !BN_bin2bn(Q->x.t.buffer, Q->x.t.size, bnX)
|| !BN_bin2bn(Q->y.t.buffer, Q->y.t.size, bnY)
|| !BN_bin2bn(curveData->p->buffer, curveData->p->size, bnP)
|| !BN_bin2bn(curveData->a->buffer, curveData->a->size, bnA)
|| !BN_set_word(bn3, 3)
|| !BN_bin2bn(curveData->b->buffer, curveData->b->size, bnB)
532 )
533 FAIL(FATAL_ERROR_INTERNAL); 534
// The following sequence is probably not optimal but it seems to be correct.
// compute x^3 + a*x + b mod p
// first, compute a*x mod p
if( !BN_mod_mul(bnA, bnA, bnX, bnP, context)
// next, compute a*x + b mod p
|| !BN_mod_add(bnA, bnA, bnB, bnP, context)
// next, compute X^3 mod p
|| !BN_mod_exp(bnX, bnX, bn3, bnP, context)
// finally, compute x^3 + a*x + b mod p
|| !BN_mod_add(bnX, bnX, bnA, bnP, context)
// then compute y^2
|| !BN_mod_mul(bnY, bnY, bnY, bnP, context)
547 )
548 | FAIL(FATAL_ERROR_INTERNAL); | |
549 | ||
550 | retVal = BN_cmp(bnX, bnY) == 0; | |
551 | BN_CTX_end(context); | |
552 | BN_CTX_free(context); | |
553 | return retVal; | |
554 | } |
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.4.1 "GKey() Pair Generation Using Extra Random Bits." 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. In this implementation, the range of the private value is further restricted to be 2^(nLen/2) <= d < n where nLen is the order of n.
EXAMPLE: If the curve is NIST-P256, then nLen is 256 bits and d will need to be between 2^128 <= d < n
It is a fatal error if Qout, dOut, or seed is not provided (is NULL).
Return Value | Meaning |
CRYPT_PARAMETER | the hash algorithm is not supported |
LIB_EXPORT CRYPT_RESULT
_cpri GenerateKeyEcc(
TPMS_ECC_POINT *Qout, // OUT: the public point
TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar
TPM_ECC_CURVE curveId, // IN: the curve identifier
TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key
// generation process
TPM2B *seed, // IN: the seed to use
const char *label, // IN: A label for the generation
// process.
TPM2B *extra, // IN: Party 1 data for the KDF
UINT32 *counter // IN/OUT: Counter value to allow KDF
// iteration to be propagated across
// multiple functions
569 )
570 {
const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
INT16 keySizeInBytes;
UINT32 count = 0;
CRYPT_RESULT retVal;
UINT16 hLen = _cpri GetDigestSize(hashAlg);
BIGNUM *bnNm1; // Order of the curve minus one
BIGNUM *bnD; // the private scalar
BN_CTX *context; // the context for the BIGNUM values
BYTE withExtra[MAX_ECC_KEY_BYTES + 8]; // trial key with
//extra bits
TPM2B_4_BYTE_VALUE marshaledCounter = {4, {0}};
UINT32 totalBits; 583
584 // Validate parameters (these are fatal)
585 pAssert( seed != NULL && dOut != NULL && Qout != NULL && curveData != NULL); 586
587 // Non-fatal parameter checks.
588 if(hLen <= 0)
589 return CRYPT_PARAMETER; 590
// allocate the local BN values
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnNm1 = BN_CTX_get(context);
bnD = BN_CTX_get(context); 598
599 // The size of the input scalars is limited by the size of the size of a 600 // TPM2B_ECC_PARAMETER. Make sure that it is not irrational.
601 pAssert((int) curveData->n->size <= MAX_ECC_KEY_BYTES); 602
603 if( bnD == NULL
604 || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnNm1) == NULL 605 || (keySizeInBytes = (INT16) BN_num_bytes(bnNm1)) > MAX_ECC_KEY_BYTES) 606 FAIL(FATAL_ERROR_INTERNAL);
607
608 // get the total number of bits
609 totalBits = BN_num_bits(bnNm1) + 64;
610
611 // Reduce bnNm1 from 'n' to 'n' - 1 612 BN_sub_word(bnNm1, 1);
613
614 // Initialize the count value 615 if(counter != NULL)
616 count = *counter; 617 if(count == 0)
618 count = 1;
619
620 // Start search for key (should be quick) 621 for(; count != 0; count++)
622 {
623
624 UINT32_TO_BYTE_ARRAY(count, marshaledCounter.t.buffer);
625 _cpri KDFa(hashAlg, seed, label, extra, &marshaledCounter.b, 626 totalBits, withExtra, NULL, FALSE);
627
628 // Convert the result and modular reduce
629 // Assume the size variables do not overflow, which should not happen in 630 // the contexts that this function will be called.
631 pAssert(keySizeInBytes <= MAX_ECC_KEY_BYTES);
632 if ( BN_bin2bn(withExtra, keySizeInBytes+8, bnD) == NULL 633 || BN_mod(bnD, bnD, bnNm1, context) != 1)
634 FAIL(FATAL_ERROR_INTERNAL);
635
636 // Add one to get 0 < d < n
637 BN_add_word(bnD, 1);
638 if(BnTo2B(&dOut->b, bnD, keySizeInBytes) != 1)
639 FAIL(FATAL_ERROR_INTERNAL);
640
641 // Do the point multiply to create the public portion of the key. If 642 // the multiply generates the point at infinity (unlikely), do another 643 // iteration.
644 if( (retVal = _cpri EccPointMultiply(Qout, curveId, dOut, NULL, NULL)) 645 != CRYPT_NO_RESULT)
646 break;
647 }
648
649 if(count == 0) // if counter wrapped, then the TPM should go into failure mode 650 FAIL(FATAL_ERROR_INTERNAL);
651
652 // Free up allocated BN values 653 BN_CTX_end(context);
654 BN_CTX_free(context);
655 if(counter != NULL) 656 *counter = count; 657 return retVal;
658 }
This function creates an ephemeral ECC. It is ephemeral in that is expected that the private part of the key will be discarded
659 LIB_EXPORT CRYPT_RESULT
660 _cpri GetEphemeralEcc(
661 TPMS_ECC_POINT *Qout, // OUT: the public point 662 TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar
663 TPM_ECC_CURVE curveId // IN: the curve for the key 664 )
665 {
666 CRYPT_RESULT retVal;
667 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 668
669 pAssert(curveData != NULL); 670
671 // Keep getting random values until one is found that doesn't create a point 672 // at infinity. This will never, ever, ever, ever, ever, happen but if it does 673 // we have to get a next random value.
674 while(TRUE)
675 {
676 GetRandomPrivate(dOut, curveData->p);
677
678 // _cpri EccPointMultiply does not return CRYPT_ECC_POINT if no point is 679 // provided. CRYPT_PARAMTER should not be returned because the curve ID 680 // has to be supported. Thus the only possible error is CRYPT_NO_RESULT. 681 retVal = _cpri EccPointMultiply(Qout, curveId, dOut, NULL, NULL);
682 if(retVal != CRYPT_NO_RESULT)
683 return retVal; // Will return CRYPT_SUCCESS 684 }
685 }
686 #ifdef TPM_ALG_ECDSA //%
This function implements the ECDSA signing algorithm. The method is described in the comments below. It is a fatal error if rOut, sOut, dIn, or digest are not provided.
687 LIB_EXPORT CRYPT_RESULT
688 SignEcdsa(
689 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature 690 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature 691 TPM_ECC_CURVE curveId, // IN: the curve used in the signature 692 // process
693 TPM2B_ECC_PARAMETER *dIn, // IN: the private key 694 TPM2B *digest // IN: the value to sign 695 )
696 {
697 BIGNUM *bnK;
698 BIGNUM *bnIk;
699 BIGNUM *bnN;
700 BIGNUM *bnR;
701 | BIGNUM *bnD; | |
702 | BIGNUM *bnZ; | |
703 | TPM2B_ECC_PARAMETER k; | |
704 | TPMS_ECC_POINT R; | |
705 | BN_CTX *context; | |
706 | CRYPT_RESULT retVal = CRYPT_SUCCESS; | |
707 | const ECC_CURVE_DATA *curveData = GetCurveData(curveId); | |
708 | ||
709 | pAssert(rOut != NULL && sOut != NULL && dIn != NULL && digest != NULL); | |
710 | ||
711 | context = BN_CTX_new(); | |
712 | if(context == NULL) | |
713 | FAIL(FATAL_ERROR_ALLOCATION); | |
714 | BN_CTX_start(context); | |
715 | bnN = BN_CTX_get(context); | |
716 | bnZ = BN_CTX_get(context); | |
717 | bnR = BN_CTX_get(context); | |
718 | bnD = BN_CTX_get(context); | |
719 | bnIk = BN_CTX_get(context); | |
720 | bnK = BN_CTX_get(context); | |
721 | // Assume the size variables do not overflow, which should not happen in | |
722 | // the contexts that this function will be called. | |
723 | pAssert(curveData->n->size <= MAX_ECC_PARAMETER_BYTES); | |
724 | if( bnK == NULL | |
725 | || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL) | |
726 | FAIL(FATAL_ERROR_INTERNAL); | |
727 | ||
728 | // | The algorithm as described in "Suite B Implementer's Guide to FIPS 186-3(ECDSA)" |
729 | // | 1. Use one of the routines in Appendix A.2 to generate (k, k^-1), a per-message |
730 | // | secret number and its inverse modulo n. Since n is prime, the |
731 | // | output will be invalid only if there is a failure in the RBG. |
732 | // | 2. Compute the elliptic curve point R = [k]G = (xR, yR) using EC scalar |
733 | // | multiplication (see [Routines]), where G is the base point included in |
734 | // | the set of domain parameters. |
735 | // | 3. Compute r = xR mod n. If r = 0, then return to Step 1. 1. |
736 | // | 4. Use the selected hash function to compute H = Hash(M). |
737 | // | 5. Convert the bit string H to an integer e as described in Appendix B.2. |
738 | // | 6. Compute s = (k^-1 * (e + d * r)) mod n. If s = 0, return to Step 1.2. |
739 | // | 7. Return (r, s). |
740 | ||
741 | // Generate a random value k in the range 1 <= k < n | |
742 | // Want a K value that is the same size as the curve order | |
743 | k.t.size = curveData->n->size; | |
744 | ||
745 | while(TRUE) // This implements the loop at step 6. If s is zero, start over. | |
746 | { | |
747 | while(TRUE) | |
748 | { | |
749 | // Step 1 and 2 -- generate an ephemeral key and the modular inverse | |
750 | // of the private key. | |
751 | while(TRUE) | |
752 | { | |
753 | GetRandomPrivate(&k, curveData->n); | |
754 | ||
755 | // Do the point multiply to generate a point and check to see if | |
756 | // the point it at infinity | |
757 | if( _cpri EccPointMultiply(&R, curveId, &k, NULL, NULL) | |
758 | != CRYPT_NO_RESULT) | |
759 | break; // can only be CRYPT_SUCCESS | |
760 | } | |
761 | ||
762 | // x coordinate is mod p. Make it mod n | |
763 | // Assume the size variables do not overflow, which should not happen | |
764 | // in the contexts that this function will be called. | |
765 | assert2Bsize(R.x.t); | |
766 | BN_bin2bn(R.x.t.buffer, R.x.t.size, bnR); |
767 | BN_mod(bnR, bnR, bnN, context); | |
768 | ||
769 | // Make sure that it is not zero; | |
770 | if(BN_is_zero(bnR)) | |
771 | continue; | |
772 | ||
773 | // Make sure that a modular inverse exists | |
774 | // Assume the size variables do not overflow, which should not | happen |
775 | // in the contexts that this function will be called. | |
776 | assert2Bsize(k.t); | |
777 | BN_bin2bn(k.t.buffer, k.t.size, bnK); | |
778 | if( BN_mod_inverse(bnIk, bnK, bnN, context) != NULL) |
779 break;
780 }
781
782 // Set z = leftmost bits of the digest
783 // NOTE: This is implemented such that the key size needs to be 784 // an even number of bytes in length.
785 if(digest->size > curveData->n->size)
786 {
787 // Assume the size variables do not overflow, which should not happen 788 // in the contexts that this function will be called.
789 pAssert(curveData->n->size <= MAX_ECC_KEY_BYTES);
790 // digest is larger than n so truncate
791 BN_bin2bn(digest->buffer, curveData->n->size, bnZ); 792 }
793 else
794 {
795 // Assume the size variables do not overflow, which should not happen 796 // in the contexts that this function will be called.
797 pAssert(digest->size <= MAX_DIGEST_SIZE);
798 // digest is same or smaller than n so use it all
799 BN_bin2bn(digest->buffer, digest->size, bnZ); 800 }
801
802 // Assume the size variables do not overflow, which should not happen in 803 // the contexts that this function will be called.
804 assert2Bsize(dIn->t);
805 if( bnZ == NULL
806
807 // need the private scalar of the signing key
808 || BN_bin2bn(dIn->t.buffer, dIn->t.size, bnD) == NULL)
809 FAIL(FATAL_ERROR_INTERNAL);
810
811 // NOTE: When the result of an operation is going to be reduced mod x 812 // any modular multiplication is done so that the intermediate values 813 // don't get too large.
814 //
815 // now have inverse of K (bnIk), z (bnZ), r (bnR), d (bnD) and n (bnN) 816 // Compute s = k^-1 (z + r*d)(mod n)
817 // first do d = r*d mod n
818 if( !BN_mod_mul(bnD, bnR, bnD, bnN, context) 819
820 // d = z + r * d
821 || !BN_add(bnD, bnZ, bnD) 822
823 // d = k^(-1)(z + r * d)(mod n)
824 || !BN_mod_mul(bnD, bnIk, bnD, bnN, context) 825
826 // convert to TPM2B format
827 || !BnTo2B(&sOut->b, bnD, curveData->n->size) 828
829 // and write the modular reduced version of r
830 // NOTE: this was deferred to reduce the number of
831 // error checks.
832 || !BnTo2B(&rOut->b, bnR, curveData->n->size))
833 FAIL(FATAL_ERROR_INTERNAL);
834
835 if(!BN_is_zero(bnD))
836 break; // signature not zero so done 837
838 // if the signature value was zero, start over 839 }
840
841 // Free up allocated BN values 842 BN_CTX_end(context);
843 BN_CTX_free(context);
844 return retVal;
845 }
846 #endif //%
847 #if defined TPM_ALG_ECDAA || defined TPM_ALG_ECSCHNORR //%
This function is used to perform a modified Schnorr signature for ECDAA.
This function performs s = k + T * d mod n where
'k is a random, or pseudo-random value used in the commit phase
T is the digest to be signed, and
d is a private key.
If tIn is NULL then use tOut as T
Return Value | Meaning |
CRYPT_SUCCESS | signature created |
848 static CRYPT_RESULT
849 EcDaa(
850 TPM2B_ECC_PARAMETER *tOut, // OUT: T component of the signature 851 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature 852 TPM_ECC_CURVE curveId, // IN: the curve used in signing
853 TPM2B_ECC_PARAMETER *dIn, // IN: the private key 854 TPM2B *tIn, // IN: the value to sign
855 TPM2B_ECC_PARAMETER *kIn // IN: a random value from commit 856 )
857 {
858 BIGNUM *bnN, *bnK, *bnT, *bnD;
859 BN_CTX *context;
860 const TPM2B *n;
861 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 862 BOOL OK = TRUE;
863
864 // Parameter checks
865 pAssert( sOut != NULL && dIn != NULL && tOut != NULL 866 && kIn != NULL && curveData != NULL);
867
868 // this just saves key strokes 869 n = curveData->n;
870
871 if(tIn != NULL)
872 Copy2B(&tOut->b, tIn);
873
874 // The size of dIn and kIn input scalars is limited by the size of the size 875 // of a TPM2B_ECC_PARAMETER and tIn can be no larger than a digest.
876 // Make sure they are within range.
877 pAssert( (int) dIn->t.size <= MAX_ECC_KEY_BYTES 878 && (int) kIn->t.size <= MAX_ECC_KEY_BYTES
879 && (int) tOut->t.size <= MAX_DIGEST_SIZE
880 );
881
context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnN = BN_CTX_get(context);
bnK = BN_CTX_get(context);
bnT = BN_CTX_get(context);
bnD = BN_CTX_get(context); 890
891 // Check for allocation problems 892 if(bnD == NULL)
893 FAIL(FATAL_ERROR_ALLOCATION);
894
895 // Convert values
896 if( BN_bin2bn(n->buffer, n->size, bnN) == NULL
897 || BN_bin2bn(kIn->t.buffer, kIn->t.size, bnK) == NULL 898 || BN_bin2bn(dIn->t.buffer, dIn->t.size, bnD) == NULL 899 || BN_bin2bn(tOut->t.buffer, tOut->t.size, bnT) == NULL) 900
901 FAIL(FATAL_ERROR_INTERNAL);
902 // Compute T = T mod n
903 OK = OK && BN_mod(bnT, bnT, bnN, context); 904
905 // compute (s = k + T * d mod n) 906 // d = T * d mod n
907 OK = OK && BN_mod_mul(bnD, bnT, bnD, bnN, context) == 1; 908 // d = k + T * d mod n
909 OK = OK && BN_mod_add(bnD, bnK, bnD, bnN, context) == 1; 910 // s = d
911 OK = OK && BnTo2B(&sOut->b, bnD, n->size); 912 // r = T
913 OK = OK && BnTo2B(&tOut->b, bnT, n->size); 914 if(!OK)
915 FAIL(FATAL_ERROR_INTERNAL);
916
917 // Cleanup
918 BN_CTX_end(context);
919 BN_CTX_free(context);
920
921 return CRYPT_SUCCESS;
922 }
923 #endif //%
924 #ifdef TPM_ALG_ECSCHNORR //%
This function is used to perform a modified Schnorr signature.
This function will generate a random value k and compute
(xR, yR) = [k]G
r = hash(P || xR)(mod n)
s= k + r * ds
return the tuple T, s
Return Value | Meaning |
CRYPT_SUCCESS | signature created |
CRYPT_SCHEME | hashAlg can't produce zero-length digest |
925 static CRYPT_RESULT
926 SchnorrEcc(
927 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature 928 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature 929 TPM_ALG_ID hashAlg, // IN: hash algorithm used
930 TPM_ECC_CURVE curveId, // IN: the curve used in signing 931 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
932 TPM2B *digest, // IN: the digest to sign 933 TPM2B_ECC_PARAMETER *kIn // IN: for testing
934 )
935 {
TPM2B_ECC_PARAMETER k;
BIGNUM *bnR, *bnN, *bnK, *bnT, *bnD;
BN_CTX *context;
const TPM2B *n;
EC_POINT *pR = NULL;
EC_GROUP *group = NULL;
CPRI_HASH_STATE hashState;
UINT16 digestSize = _cpri GetDigestSize(hashAlg); 944 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
945 TPM2B_TYPE(T, MAX(MAX_DIGEST_SIZE, MAX_ECC_PARAMETER_BYTES));
946 TPM2B_T T2b;
947 BOOL OK = TRUE;
948
949 // Parameter checks 950
951 // Must have a place for the 'r' and 's' parts of the signature, a private 952 // key ('d')
953 pAssert( rOut != NULL && sOut != NULL && dIn != NULL 954 && digest != NULL && curveData != NULL);
955
956 // to save key strokes
957 n = curveData->n; 958
959 // If the digest does not produce a hash, then null the signature and return 960 // a failure.
961 if(digestSize == 0)
962 {
963 rOut->t.size = 0;
964 sOut->t.size = 0;
965 return CRYPT_SCHEME;
966 }
967
968 // Allocate big number values 969 context = BN_CTX_new();
if(context == NULL)
FAIL(FATAL_ERROR_ALLOCATION);
BN_CTX_start(context);
bnR = BN_CTX_get(context);
bnN = BN_CTX_get(context);
bnK = BN_CTX_get(context);
bnT = BN_CTX_get(context);
bnD = BN_CTX_get(context);
if( bnD == NULL
// initialize the group parameters
|| (group = EccCurveInit(curveId, context)) == NULL 981 // allocate a local point
982 || (pR = EC_POINT_new(group)) == NULL
983 )
984 | FAIL(FATAL_ERROR_ALLOCATION); | |
985 | ||
986 | if(BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL) | |
987 | FAIL(FATAL_ERROR_INTERNAL); | |
988 | ||
989 | while(OK) | |
990 | { | |
991 | // | a) set k to a random value such that 1 k n-1 |
992 | if(kIn != NULL) | |
993 | { | |
994 | Copy2B(&k.b, &kIn->b); // copy input k if testing | |
995 | OK = FALSE; // not OK to loop | |
996 | } | |
997 | else | |
998 | // If get a random value in the correct range | |
999 | GetRandomPrivate(&k, n); | |
1000 | ||
1001 | // Convert 'k' and generate pR = ['k']G | |
1002 | BnFrom2B(bnK, &k.b); | |
1003 | ||
1004 | // | b) compute E (xE, yE) [k]G |
1005 | if(PointMul(group, pR, bnK, NULL, NULL, context) == CRYPT_NO_RESULT) | |
1006 | // | c) if E is the point at infinity, go to a) |
1007 | continue; | |
1008 | ||
1009 | // | d) compute e xE (mod n) |
1010 | // Get the x coordinate of the point | |
1011 | EC_POINT_get_affine_coordinates_GFp(group, pR, bnR, NULL, context); | |
1012 | ||
1013 | // make (mod n) | |
1014 | BN_mod(bnR, bnR, bnN, context); | |
1015 | ||
1016 | // | e) if e is zero, go to a) |
1017 | if(BN_is_zero(bnR)) | |
1018 | continue; | |
1019 | ||
1020 | // Convert xR to a string (use T as a temp) | |
1021 | BnTo2B(&T2b.b, bnR, (UINT16)(BN_num_bits(bnR)+7)/8); | |
1022 | ||
1023 | // | f) compute r HschemeHash(P || e) (mod n) |
1024 | _cpri StartHash(hashAlg, FALSE, &hashState); | |
1025 | _cpri UpdateHash(&hashState, digest->size, digest->buffer); | |
1026 | _cpri UpdateHash(&hashState, T2b.t.size, T2b.t.buffer); | |
1027 | if(_cpri CompleteHash(&hashState, digestSize, T2b.b.buffer) != digestSize) | |
1028 | FAIL(FATAL_ERROR_INTERNAL); | |
1029 | T2b.t.size = digestSize; | |
1030 | BnFrom2B(bnT, &T2b.b); | |
1031 | BN_div(NULL, bnT, bnT, bnN, context); | |
1032 | BnTo2B(&rOut->b, bnT, (UINT16)BN_num_bytes(bnT)); | |
1033 | ||
1034 | // We have a value and we are going to exit the loop successfully | |
1035 | OK = TRUE; | |
1036 | break; | |
1037 | } | |
1038 | // Cleanup | |
1039 | EC_POINT_free(pR); | |
1040 | EC_GROUP_free(group); | |
1041 | BN_CTX_end(context); | |
1042 | BN_CTX_free(context); | |
1043 | ||
1044 | // If we have a value, finish the signature | |
1045 | if(OK) | |
1046 | return EcDaa(rOut, sOut, curveId, dIn, NULL, &k); | |
1047 | else | |
1048 | return CRYPT_NO_RESULT; | |
1049 | } |
1050 | #endif //% | ||||
1051 | #ifdef TPM_ALG_SM2 //% | ||||
1052 | #ifdef _SM2_SIGN_DEBUG //% | ||||
1053 | static int | ||||
1054 | cmp_bn2hex( | ||||
1055 | BIGNUM *bn, | // | IN: | big number value | |
1056 | const char *c | // | IN: | character string number | |
1057 | ) | ||||
1058 | { | ||||
1059 | int result; | ||||
1060 | BIGNUM *bnC = BN_new(); | ||||
1061 | pAssert(bnC != NULL); | ||||
1062 | |||||
1063 | BN_hex2bn(&bnC, c); | ||||
1064 | result = BN_ucmp(bn, bnC); | ||||
1065 | BN_free(bnC); | ||||
1066 | return result; | ||||
1067 | } | ||||
1068 | static int | ||||
1069 | cmp_2B2hex( | ||||
1070 | TPM2B *a, | // | IN: | TPM2B number to compare | |
1071 | const char *c | // | IN: | character string | |
1072 | ) | ||||
1073 | { | ||||
1074 | int result; | ||||
1075 | int sl = strlen(c); | ||||
1076 | BIGNUM *bnA; | ||||
1077 | |||||
1078 | result = (a->size * 2) - sl; | ||||
1079 | if(result != 0) | ||||
1080 | return result; | ||||
1081 | pAssert((bnA = BN_bin2bn(a->buffer, a->size, NULL)) != NULL); | ||||
1082 | result = cmp_bn2hex(bnA, c); | ||||
1083 | BN_free(bnA); | ||||
1084 | return result; | ||||
1085 | } | ||||
1086 | static void | ||||
1087 | cpy_hexTo2B( | ||||
1088 | TPM2B *b, // OUT: receives value | ||||
1089 | const char *c // IN: source string | ||||
1090 | ) | ||||
1091 | { | ||||
1092 | BIGNUM *bnB = BN_new(); | ||||
1093 | pAssert((strlen(c) & 1) == 0); // must have an even number of | digits | |||
1094 | b->size = strlen(c) / 2; | ||||
1095 | BN_hex2bn(&bnB, c); | ||||
1096 | pAssert(bnB != NULL); | ||||
1097 | BnTo2B(b, bnB, b->size); | ||||
1098 | BN_free(bnB); | ||||
1099 | |||||
1100 | } | ||||
1101 | #endif //% _SM2_SIGN_DEBUG |
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) that is signed. This function signs e.
Return Value | Meaning |
CRYPT_SUCCESS | sign worked |
1102 static CRYPT_RESULT
1103 SignSM2(
1104 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature 1105 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature 1106 TPM_ECC_CURVE curveId, // IN: the curve used in signing 1107 TPM2B_ECC_PARAMETER *dIn, // IN: the private key
1108 TPM2B *digest // IN: the digest to sign 1109 )
1110 {
1111 BIGNUM *bnR;
1112 BIGNUM *bnS;
1113 BIGNUM *bnN;
1114 BIGNUM *bnK;
1115 BIGNUM *bnX1;
1116 BIGNUM *bnD;
1117 BIGNUM *bnT; // temp
1118 BIGNUM *bnE;
1119
1120 BN_CTX *context;
1121 TPM2B_TYPE(DIGEST, MAX_DIGEST_SIZE);
1122 TPM2B_ECC_PARAMETER k;
1123 TPMS_ECC_POINT p2Br;
1124 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 1125
1126 pAssert(curveData != NULL); 1127 context = BN_CTX_new();
1128 BN_CTX_start(context); 1129 bnK = BN_CTX_get(context); 1130 bnR = BN_CTX_get(context); 1131 bnS = BN_CTX_get(context);
1132 bnX1 = BN_CTX_get(context); 1133 bnN = BN_CTX_get(context); 1134 bnD = BN_CTX_get(context); 1135 bnT = BN_CTX_get(context); 1136 bnE = BN_CTX_get(context); 1137 if(bnE == NULL)
1138 FAIL(FATAL_ERROR_ALLOCATION);
1139
1140 BnFrom2B(bnE, digest);
1141 BnFrom2B(bnN, curveData->n);
1142 BnFrom2B(bnD, &dIn->b);
1143
1144 #ifdef _SM2_SIGN_DEBUG
1145 BN_hex2bn(&bnE, "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76");
1146 BN_hex2bn(&bnD, "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263");
1147 #endif
1148 // A3: Use random number generator to generate random number 1 <= k <= n-1; 1149 // NOTE: Ax: numbers are from the SM2 standard
1150 k.t.size = curveData->n->size; 1151 loop:
1152 {
1153 // Get a random number
1154 _cpri GenerateRandom(k.t.size, k.t.buffer);
1155
1156 #ifdef _SM2_SIGN_DEBUG
1157 BN_hex2bn(&bnK, "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F");
1158 BnTo2B(&k.b,bnK, 32);
1159 k.t.size = 32;
1160 #endif
1161 //make sure that the number is 0 < k < n
1162 BnFrom2B(bnK, &k.b);
1163 if( BN_ucmp(bnK, bnN) >= 0
1164 || BN_is_zero(bnK))
1165 goto loop;
1166
1167 // A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according 1168 // to details specified in 4.2.7 in Part 1 of this document, transform the 1169 // data type of x1 into an integer;
1170 if( _cpri EccPointMultiply(&p2Br, curveId, &k, NULL, NULL) 1171 == CRYPT_NO_RESULT)
1172 goto loop;
1173
1174 BnFrom2B(bnX1, &p2Br.x.b);
1175
1176 // A5: Figure out r = (e + x1) mod n,
1177 if(!BN_mod_add(bnR, bnE, bnX1, bnN, context)) 1178 FAIL(FATAL_ERROR_INTERNAL);
1179 #ifdef _SM2_SIGN_DEBUG
1180 pAssert(cmp_bn2hex(bnR,
1181 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1")
1182 == 0);
1183 #endif
1184
1185 // if r=0 or r+k=n, return to A3; 1186 if(!BN_add(bnT, bnK, bnR))
1187 FAIL(FATAL_ERROR_INTERNAL);
1188
1189 if(BN_is_zero(bnR) || BN_ucmp(bnT, bnN) == 0) 1190 goto loop;
1191
1192 // A6: Figure out s = ((1 + dA)^-1 (k - r dA)) mod n, if s=0, return to A3; 1193 // compute t = (1+d)-1
1194 BN_copy(bnT, bnD);
1195 if( !BN_add_word(bnT, 1)
1196 || !BN_mod_inverse(bnT, bnT, bnN, context) // (1 + dA)^-1 mod n 1197 )
1198 FAIL(FATAL_ERROR_INTERNAL);
1199 #ifdef _SM2_SIGN_DEBUG
1200 pAssert(cmp_bn2hex(bnT,
1201 "79BFCF3052C80DA7B939E0C6914A18CBB2D96D8555256E83122743A7D4F5F956")
1202 == 0);
1203 #endif
1204 // compute s = t * (k - r * dA) mod n
1205 if( !BN_mod_mul(bnS, bnD, bnR, bnN, context) // (r * dA) mod n
1206 || !BN_mod_sub(bnS, bnK, bnS, bnN, context) // (k - (r * dA) mod n 1207 || !BN_mod_mul(bnS, bnT, bnS, bnN, context))// t * (k - (r * dA) mod n 1208 FAIL(FATAL_ERROR_INTERNAL);
1209 #ifdef _SM2_SIGN_DEBUG
1210 pAssert(cmp_bn2hex(bnS,
1211 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")
1212 == 0);
1213 #endif
1214
1215 if(BN_is_zero(bnS))
1216 goto loop;
1217 }
1218
1219 // A7: According to details specified in 4.2.1 in Part 1 of this document, transform 1220 // the data type of r, s into bit strings, signature of message M is (r, s).
1221
1222 BnTo2B(&rOut->b, bnR, curveData->n->size); 1223 BnTo2B(&sOut->b, bnS, curveData->n->size); 1224 #ifdef _SM2_SIGN_DEBUG
1225 pAssert(cmp_2B2hex(&rOut->b,
1226 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1")
1227 == 0);
1228 pAssert(cmp_2B2hex(&sOut->b,
1229 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7")
1230 == 0);
1231 #endif
1232 BN_CTX_end(context);
1233 BN_CTX_free(context);
1234 return CRYPT_SUCCESS;
1235 }
1236 #endif //% TPM_ALG_SM2
This function is the dispatch function for the various ECC-based signing schemes.
Return Value | Meaning |
CRYPT_SCHEME | scheme is not supported |
1237 LIB_EXPORT CRYPT_RESULT
1238 _cpri SignEcc(
1239 TPM2B_ECC_PARAMETER *rOut, // OUT: r component of the signature 1240 TPM2B_ECC_PARAMETER *sOut, // OUT: s component of the signature 1241 TPM_ALG_ID scheme, // IN: the scheme selector
1242 TPM_ALG_ID hashAlg, // IN: the hash algorithm if need
1243 TPM_ECC_CURVE curveId, // IN: the curve used in the signature 1244 // process
1245 TPM2B_ECC_PARAMETER *dIn, // IN: the private key 1246 TPM2B *digest, // IN: the digest to sign 1247 TPM2B_ECC_PARAMETER *kIn // IN: k for input
1248 )
1249 {
1250 switch (scheme)
1251 {
1252 case TPM_ALG_ECDSA:
1253 // SignEcdsa always works
1254 return SignEcdsa(rOut, sOut, curveId, dIn, digest);
1255 break;
1256 #ifdef TPM_ALG_ECDAA
1257 case TPM_ALG_ECDAA:
1258 if(rOut != NULL)
1259 rOut->b.size = 0;
1260 return EcDaa(rOut, sOut, curveId, dIn, digest, kIn);
1261 break;
1262 #endif
1263 #ifdef TPM_ALG_ECSCHNORR
1264 case TPM_ALG_ECSCHNORR:
1265 return SchnorrEcc(rOut, sOut, hashAlg, curveId, dIn, digest, kIn); 1266 break;
1267 #endif
1268 #ifdef TPM_ALG_SM2
1269 case TPM_ALG_SM2:
1270 return SignSM2(rOut, sOut, curveId, dIn, digest);
1271 break;
1272 #endif
1273 default:
1274 | return CRYPT_SCHEME; | |
1275 | } | |
1276 | } | |
1277 | #ifdef | TPM_ALG_ECDSA //% |
This function validates an ECDSA signature. rIn and sIn shoudl have been checked to make sure that they are not zero.
Return Value | Meaning |
CRYPT_SUCCESS | signature valid |
CRYPT_FAIL | signature not valid |
1278 static CRYPT_RESULT
1279 ValidateSignatureEcdsa(
1280 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature 1281 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature 1282 TPM_ECC_CURVE curveId, // IN: the curve used in the signature 1283 // process
1284 TPMS_ECC_POINT *Qin, // IN: the public point of the key 1285 TPM2B *digest // IN: the digest that was signed 1286 )
1287 {
1288 TPM2B_ECC_PARAMETER U1;
1289 TPM2B_ECC_PARAMETER U2;
1290 TPMS_ECC_POINT R;
1291 const TPM2B *n;
1292 BN_CTX *context;
1293 EC_POINT *pQ = NULL;
1294 EC_GROUP *group = NULL;
1295 BIGNUM *bnU1;
1296 BIGNUM *bnU2;
1297 BIGNUM *bnR;
1298 BIGNUM *bnS;
1299 BIGNUM *bnW;
1300 BIGNUM *bnV;
1301 BIGNUM *bnN;
1302 BIGNUM *bnE;
1303 BIGNUM *bnGx;
1304 BIGNUM *bnGy;
1305 BIGNUM *bnQx;
1306 BIGNUM *bnQy;
1307 CRYPT_RESULT retVal = CRYPT_FAIL;
1308 int t;
1309
1310 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 1311
1312 // The curve selector should have been filtered by the unmarshaling process 1313 pAssert (curveData != NULL);
1314 n = curveData->n; 1315
1316 // 1. If r and s are not both integers in the interval [1, n - 1], output 1317 // INVALID.
1318 // rIn and sIn are known to be greater than zero (was checked by the caller). 1319 if( _math uComp(rIn->t.size, rIn->t.buffer, n->size, n->buffer) >= 0 1320 || _math uComp(sIn->t.size, sIn->t.buffer, n->size, n->buffer) >= 0 1321 )
1322 return CRYPT_FAIL;
1323
1324 context = BN_CTX_new();
1325 if(context == NULL)
1326 FAIL(FATAL_ERROR_ALLOCATION);
1327 BN_CTX_start(context); 1328 bnR = BN_CTX_get(context); 1329 bnS = BN_CTX_get(context); 1330 bnN = BN_CTX_get(context); 1331 bnE = BN_CTX_get(context); 1332 bnV = BN_CTX_get(context); 1333 bnW = BN_CTX_get(context);
1334 bnGx = BN_CTX_get(context); 1335 bnGy = BN_CTX_get(context); 1336 bnQx = BN_CTX_get(context);
1337 | bnQy = BN_CTX_get(context); | |
1338 | bnU1 = BN_CTX_get(context); | |
1339 | bnU2 = BN_CTX_get(context); | |
1340 | ||
1341 | // Assume the size variables do not overflow, which should not happen in | |
1342 | // the contexts that this function will be called. | |
1343 | assert2Bsize(Qin->x.t); | |
1344 | assert2Bsize(rIn->t); | |
1345 | assert2Bsize(sIn->t); | |
1346 | ||
1347 | // BN_CTX_get() is sticky so only need to check the last value to know that | |
1348 | // all worked. | |
1349 | if( bnU2 == NULL | |
1350 | ||
1351 | // initialize the group parameters | |
1352 | || (group = EccCurveInit(curveId, context)) == NULL | |
1353 | ||
1354 | // allocate a local point | |
1355 | || (pQ = EC_POINT_new(group)) == NULL | |
1356 | ||
1357 | // use the public key values (QxIn and QyIn) to initialize Q | |
1358 | || BN_bin2bn(Qin->x.t.buffer, Qin->x.t.size, bnQx) == NULL | |
1359 | || BN_bin2bn(Qin->x.t.buffer, Qin->x.t.size, bnQy) == NULL | |
1360 | || !EC_POINT_set_affine_coordinates_GFp(group, pQ, bnQx, bnQy, context) | |
1361 | ||
1362 | // convert the signature values | |
1363 | || BN_bin2bn(rIn->t.buffer, rIn->t.size, bnR) == NULL | |
1364 | || BN_bin2bn(sIn->t.buffer, sIn->t.size, bnS) == NULL | |
1365 | ||
1366 | // convert the curve order | |
1367 | || BN_bin2bn(curveData->n->buffer, curveData->n->size, bnN) == NULL) | |
1368 | FAIL(FATAL_ERROR_INTERNAL); | |
1369 | ||
1370 | // | 2. Use the selected hash function to compute H0 = Hash(M0). |
1371 | // This is an input parameter | |
1372 | ||
1373 | // | 3. Convert the bit string H0 to an integer e as described in Appendix B.2. |
1374 | t = (digest->size > rIn->t.size) ? rIn->t.size : digest->size; | |
1375 | if(BN_bin2bn(digest->buffer, t, bnE) == NULL) | |
1376 | FAIL(FATAL_ERROR_INTERNAL); | |
1377 | ||
1378 | // | 4. Compute w = (s')^-1 mod n, using the routine in Appendix B.1. |
1379 | if (BN_mod_inverse(bnW, bnS, bnN, context) == NULL) | |
1380 | FAIL(FATAL_ERROR_INTERNAL); | |
1381 | ||
1382 | // | 5. Compute u1 = (e' * w) mod n, and compute u2 = (r' * w) mod n. |
1383 | if( !BN_mod_mul(bnU1, bnE, bnW, bnN, context) | |
1384 | || !BN_mod_mul(bnU2, bnR, bnW, bnN, context)) | |
1385 | FAIL(FATAL_ERROR_INTERNAL); | |
1386 | ||
1387 | BnTo2B(&U1.b, bnU1, (INT16) BN_num_bytes(bnU1)); | |
1388 | BnTo2B(&U2.b, bnU2, (INT16) BN_num_bytes(bnU2)); | |
1389 | ||
1390 | // | 6. Compute the elliptic curve point R = (xR, yR) = u1G+u2Q, using EC |
1391 | // | scalar multiplication and EC addition (see [Routines]). If R is equal to |
1392 | // | the point at infinity O, output INVALID. |
1393 | if(_cpri EccPointMultiply(&R, curveId, &U1, Qin, &U2) == CRYPT_SUCCESS) | |
1394 | { | |
1395 | // 7. Compute v = Rx mod n. | |
1396 | if( BN_bin2bn(R.x.t.buffer, R.x.t.size, bnV) == NULL | |
1397 | || !BN_mod(bnV, bnV, bnN, context)) | |
1398 | FAIL(FATAL_ERROR_INTERNAL); | |
1399 | ||
1400 | // 8. Compare v and r0. If v = r0, output VALID; otherwise, output INVALID | |
1401 | if(BN_cmp(bnV, bnR) == 0) | |
1402 | retVal = CRYPT_SUCCESS; |
1403 }
1404
1405 if(pQ != NULL) EC_POINT_free(pQ);
1406 if(group != NULL) EC_GROUP_free(group); 1407 BN_CTX_end(context);
1408 BN_CTX_free(context);
1409
1410 return retVal;
1411 }
1412 #endif //% TPM_ALG_ECDSA
1413 #ifdef TPM_ALG_ECSCHNORR //%
This function is used to validate an EC Schnorr signature. rIn and sIn are required to be greater than zero. This is checked in _cpri__ValidateSignatureEcc().
Return Value | Meaning |
CRYPT_SUCCESS | signature valid |
CRYPT_FAIL | signature not valid |
CRYPT_SCHEME | hashAlg is not supported |
1414 static CRYPT_RESULT
1415 ValidateSignatureEcSchnorr(
1416 TPM2B_ECC_PARAMETER *rIn, // IN: r component of the signature 1417 TPM2B_ECC_PARAMETER *sIn, // IN: s component of the signature 1418 TPM_ALG_ID hashAlg, // IN: hash algorithm of the signature 1419 TPM_ECC_CURVE curveId, // IN: the curve used in the signature 1420 // process
1421 TPMS_ECC_POINT *Qin, // IN: the public point of the key 1422 TPM2B *digest // IN: the digest that was signed 1423 )
1424 {
1425 TPMS_ECC_POINT pE;
1426 const TPM2B *n;
1427 CPRI_HASH_STATE hashState;
1428 TPM2B_DIGEST rPrime;
1429 TPM2B_ECC_PARAMETER minusR;
1430 UINT16 digestSize = _cpri GetDigestSize(hashAlg); 1431 const ECC_CURVE_DATA *curveData = GetCurveData(curveId);
1432
1433 // The curve parameter should have been filtered by unmarshaling code 1434 pAssert(curveData != NULL);
1435
1436 if(digestSize == 0)
1437 return CRYPT_SCHEME;
1438
1439 // Input parameter validation
1440 pAssert(rIn != NULL && sIn != NULL && Qin != NULL && digest != NULL); 1441
1442 n = curveData->n; 1443
1444 // if sIn or rIn are not between 1 and N-1, signature check fails 1445 // sIn and rIn were verified to be non-zero by the caller
1446 if( _math uComp(sIn->b.size, sIn->b.buffer, n->size, n->buffer) >= 0 1447 || _math uComp(rIn->b.size, rIn->b.buffer, n->size, n->buffer) >= 0 1448 )
1449 return CRYPT_FAIL;
1450
1451 //E = [s]InG - [r]InQ
1452 _math sub(n->size, n->buffer,
1453 rIn->t.size, rIn->t.buffer,
1454 &minusR.t.size, minusR.t.buffer);
1455 if(_cpri EccPointMultiply(&pE, curveId, sIn, Qin, &minusR) != CRYPT_SUCCESS) 1456 return CRYPT_FAIL;
1457
1458 // Ex = Ex mod N
1459 if(Mod2B(&pE.x.b, n) != CRYPT_SUCCESS)
1460 FAIL(FATAL_ERROR_INTERNAL);
1461
1462 _math Normalize2B(&pE.x.b);
1463
1464 // rPrime = h(digest || pE.x) mod n;
1465 _cpri StartHash(hashAlg, FALSE, &hashState);
1466 _cpri UpdateHash(&hashState, digest->size, digest->buffer); 1467 _cpri UpdateHash(&hashState, pE.x.t.size, pE.x.t.buffer);
1468 if(_cpri CompleteHash(&hashState, digestSize, rPrime.t.buffer) != digestSize) 1469 FAIL(FATAL_ERROR_INTERNAL);
1470
1471 rPrime.t.size = digestSize; 1472
1473 // rPrime = rPrime (mod n)
1474 if(Mod2B(&rPrime.b, n) != CRYPT_SUCCESS)
1475 FAIL(FATAL_ERROR_INTERNAL);
1476
1477 // if the values don't match, then the signature is bad 1478 if(_math uComp(rIn->t.size, rIn->t.buffer,
1479 rPrime.t.size, rPrime.t.buffer) != 0)
1480 return CRYPT_FAIL;
1481 else
1482 return CRYPT_SUCCESS;
1483 }
1484 #endif //% TPM_ALG_ECSCHNORR
1485 #ifdef TPM_ALG_SM2 //%
This function is used to validate an SM2 signature.
Return Value | Meaning |
CRYPT_SUCCESS | signature valid |
CRYPT_FAIL | signature not valid |
1486 | static CRYPT_RESULT | |
1487 | ValidateSignatureSM2Dsa( | |
1488 | TPM2B_ECC_PARAMETER | *rIn, // IN: r component of the signature |
1489 | TPM2B_ECC_PARAMETER | *sIn, // IN: s component of the signature |
1490 | TPM_ECC_CURVE | curveId, // IN: the curve used in the signature |
1491 | // process | |
1492 | TPMS_ECC_POINT | *Qin, // IN: the public point of the key |
1493 | TPM2B | *digest // IN: the digest that was signed |
1494 | ) | |
1495 | { | |
1496 | BIGNUM | *bnR; |
1497 | BIGNUM | *bnRp; |
1498 | BIGNUM | *bnT; |
1499 | BIGNUM | *bnS; |
1500 | BIGNUM | *bnE; |
1501 | EC_POINT | *pQ; |
1502 | BN_CTX | *context; |
1503 | EC_GROUP | *group = NULL; |
1504 | const ECC_CURVE_DATA | *curveData = GetCurveData(curveId); |
1505 | BOOL | fail = FALSE; |
1506 |
1507 if((context = BN_CTX_new()) == NULL || curveData == NULL) 1508 FAIL(FATAL_ERROR_INTERNAL);
1509 bnR = BN_CTX_get(context); 1510 bnRp= BN_CTX_get(context); 1511 bnE = BN_CTX_get(context); 1512 bnT = BN_CTX_get(context); 1513 bnS = BN_CTX_get(context); 1514 if( bnS == NULL
1515 || (group = EccCurveInit(curveId, context)) == NULL) 1516 FAIL(FATAL_ERROR_INTERNAL);
1517
1518 #ifdef _SM2_SIGN_DEBUG
1519 cpy_hexTo2B(&Qin->x.b,
1520 "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A");
1521 cpy_hexTo2B(&Qin->y.b,
1522 "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857");
1523 cpy_hexTo2B(digest,
1524 "B524F552CD82B8B028476E005C377FB19A87E6FC682D48BB5D42E3D9B9EFFE76");
1525 #endif
1526 pQ = EccInitPoint2B(group, Qin, context); 1527
1528 #ifdef _SM2_SIGN_DEBUG
1529 pAssert(EC_POINT_get_affine_coordinates_GFp(group, pQ, bnT, bnS, context)); 1530 pAssert(cmp_bn2hex(bnT,
1531 "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A")
1532 == 0);
1533 pAssert(cmp_bn2hex(bnS,
1534 "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857")
1535 == 0);
1536 #endif
1537
1538 BnFrom2B(bnR, &rIn->b);
1539 BnFrom2B(bnS, &sIn->b);
1540 BnFrom2B(bnE, digest);
1541
1542 #ifdef _SM2_SIGN_DEBUG
1543 // Make sure that the input signature is the test signature 1544 pAssert(cmp_2B2hex(&rIn->b,
1545 "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1") == 0);
1546 pAssert(cmp_2B2hex(&sIn->b,
1547 "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7") == 0);
1548 #endif
1549
1550 // a) verify that r and s are in the inclusive interval 1 to (n 1) 1551 fail = (BN_ucmp(bnR, &group->order) >= 0);
1552
1553 fail = (BN_ucmp(bnS, &group->order) >= 0) || fail; 1554 if(fail)
1555 // There is no reason to continue. Since r and s are inputs from the caller, 1556 // they can know that the values are not in the proper range. So, exiting here 1557 // does not disclose any information.
1558 goto Cleanup;
1559
1560 // b) compute t := (r + s) mod n
1561 if(!BN_mod_add(bnT, bnR, bnS, &group->order, context)) 1562 FAIL(FATAL_ERROR_INTERNAL);
1563 #ifdef _SM2_SIGN_DEBUG
1564 pAssert(cmp_bn2hex(bnT,
1565 "2B75F07ED7ECE7CCC1C8986B991F441AD324D6D619FE06DD63ED32E0C997C801")
1566 == 0);
1567 #endif
1568
1569 // c) verify that t > 0 1570 if(BN_is_zero(bnT)) { 1571 fail = TRUE;
1572 // set to a value that should allow rest of the computations to run without
1573 // trouble
1574 BN_copy(bnT, bnS);
1575 }
1576 // d) compute (x, y) := [s]G + [t]Q
1577 if(!EC_POINT_mul(group, pQ, bnS, pQ, bnT, context)) 1578 FAIL(FATAL_ERROR_INTERNAL);
1579 // Get the x coordinate of the point
1580 if(!EC_POINT_get_affine_coordinates_GFp(group, pQ, bnT, NULL, context)) 1581 FAIL(FATAL_ERROR_INTERNAL);
1582
1583 #ifdef _SM2_SIGN_DEBUG
1584 pAssert(cmp_bn2hex(bnT,
1585 "110FCDA57615705D5E7B9324AC4B856D23E6D9188B2AE47759514657CE25D112")
1586 == 0);
1587 #endif
1588
1589 // e) compute r' := (e + x) mod n (the x coordinate is in bnT) 1590 if(!BN_mod_add(bnRp, bnE, bnT, &group->order, context)) 1591 FAIL(FATAL_ERROR_INTERNAL);
1592
1593 // f) verify that r' = r
1594 fail = BN_ucmp(bnR, bnRp) != 0 || fail; 1595
1596 Cleanup:
1597 if(pQ) EC_POINT_free(pQ);
1598 if(group) EC_GROUP_free(group);
1599 BN_CTX_end(context);
1600 BN_CTX_free(context);
1601
1602 if(fail)
1603 return CRYPT_FAIL;
1604 else
1605 return CRYPT_SUCCESS;
1606 }
1607 #endif //% TPM_ALG_SM2
_cpri__ValidateSignatureEcc()
This function validates
Return Value | Meaning |
CRYPT_SUCCESS | signature is valid |
CRYPT_FAIL | not a valid signature |
CRYPT_SCHEME | unsupported scheme |
1608 | LIB_EXPORT CRYPT_RESULT | |||
1609 | _cpri ValidateSignatureEcc( | |||
1610 | TPM2B_ECC_PARAMETER *rIn, | // | IN: | r component of the signature |
1611 | TPM2B_ECC_PARAMETER *sIn, | // | IN: | s component of the signature |
1612 | TPM_ALG_ID scheme, | // | IN: | the scheme selector |
1613 | TPM_ALG_ID hashAlg, | // | IN: | the hash algorithm used (not used |
1614 | // | in all schemes) | ||
1615 | TPM_ECC_CURVE curveId, | // | IN: | the curve used in the signature |
1616 | // | process | ||
1617 | TPMS_ECC_POINT *Qin, | // | IN: | the public point of the key |
1618 | TPM2B *digest | // | IN: | the digest that was signed |
1619 | ) | |||
1620 | { | |||
1621 | CRYPT_RESULT retVal; | |||
1622 |
1623 // return failure if either part of the signature is zero
1624 if(_math Normalize2B(&rIn->b) == 0 || _math Normalize2B(&sIn->b) == 0)
1625 return CRYPT_FAIL;
1626
1627 switch (scheme)
1628 {
1629 case TPM_ALG_ECDSA:
1630 retVal = ValidateSignatureEcdsa(rIn, sIn, curveId, Qin, digest); 1631 break;
1632
1633 #ifdef TPM_ALG_ECSCHNORR
1634 case TPM_ALG_ECSCHNORR:
1635 retVal = ValidateSignatureEcSchnorr(rIn, sIn, hashAlg, curveId, Qin, 1636 digest);
1637 break;
1638 #endif
1639
1640 #ifdef TPM_ALG_SM2
1641 case TPM_ALG_SM2:
1642 retVal = ValidateSignatureSM2Dsa(rIn, sIn, curveId, Qin, digest); 1643 #endif
1644 default:
1645 retVal = CRYPT_SCHEME;
1646 break;
1647 }
1648 return retVal;
1649 }
1650 #if CC_ZGen_2Phase == YES //%
1651 #ifdef TPM_ALG_ECMQV
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)
1652 static BOOL
1653 avf1(
1654 BIGNUM *bnX, // IN/OUT: the reduced value 1655 BIGNUM *bnN // IN: the order of the curve 1656 )
1657 {
1658 // compute f = 2^(ceil(ceil(log2(n)) / 2))
1659 int f = (BN_num_bits(bnN) + 1) / 2; 1660 // x' = 2^f + (x mod 2^f)
1661 BN_mask_bits(bnX, f); // This is mod 2*2^f but it doesn't matter because 1662 // the next operation will SET the extra bit anyway 1663 BN_set_bit(bnX, f);
1664 return TRUE;
1665 }
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.
Return Value | Meaning |
CRYPT_SUCCESS | results is valid |
CRYPT_NO_RESULT | the value for dsA does not give a valid point on the curve |
1666 | static CRYPT_RESULT | |
1667 | C_2_2_MQV( | |
1668 | TPMS_ECC_POINT *outZ, // OUT: the computed point | |
1669 | TPM_ECC_CURVE curveId, // IN: the curve for the computations | |
1670 | TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key | |
1671 | TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key | |
1672 | TPMS_ECC_POINT *QsB, // IN: static public party B key | |
1673 | TPMS_ECC_POINT *QeB // IN: ephemeral public party B key | |
1674 | ) | |
1675 | { | |
1676 | BN_CTX *context; | |
1677 | EC_POINT *pQeA = NULL; | |
1678 | EC_POINT *pQeB = NULL; | |
1679 | EC_POINT *pQsB = NULL; | |
1680 | EC_GROUP *group = NULL; | |
1681 | BIGNUM *bnTa; | |
1682 | BIGNUM *bnDeA; | |
1683 | BIGNUM *bnDsA; | |
1684 | BIGNUM *bnXeA; // x coordinate of ephemeral party A | key |
1685 | BIGNUM *bnH; | |
1686 | BIGNUM *bnN; | |
1687 | BIGNUM *bnXeB; | |
1688 | const ECC_CURVE_DATA *curveData = GetCurveData(curveId); | |
1689 | CRYPT_RESULT retVal; | |
1690 | ||
1691 | pAssert( curveData != NULL && outZ != NULL && dsA != NULL | |
1692 | && deA != NULL && QsB != NULL && QeB != NULL); | |
1693 | ||
1694 | context = BN_CTX_new(); | |
1695 | if(context == NULL || curveData == NULL) | |
1696 | FAIL(FATAL_ERROR_ALLOCATION); | |
1697 | BN_CTX_start(context); | |
1698 | bnTa = BN_CTX_get(context); | |
1699 | bnDeA = BN_CTX_get(context); | |
1700 | bnDsA = BN_CTX_get(context); | |
1701 | bnXeA = BN_CTX_get(context); | |
1702 | bnH = BN_CTX_get(context); | |
1703 | bnN = BN_CTX_get(context); | |
1704 | bnXeB = BN_CTX_get(context); | |
1705 | if(bnXeB == NULL) | |
1706 | FAIL(FATAL_ERROR_ALLOCATION); | |
1707 | ||
1708 | // Process: | |
1709 | // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n. | |
1710 | // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B). | |
1711 | // 3. If P = O, output an error indicator. | |
1712 | // 4. Z=xP, where xP is the x-coordinate of P. | |
1713 | ||
1714 | // Initialize group parameters and local values of input | |
1715 | if((group = EccCurveInit(curveId, context)) == NULL) | |
1716 | FAIL(FATAL_ERROR_INTERNAL); | |
1717 | ||
1718 | if((pQeA = EC_POINT_new(group)) == NULL) | |
1719 | FAIL(FATAL_ERROR_ALLOCATION); | |
1720 | ||
1721 | BnFrom2B(bnDeA, &deA->b); | |
1722 | BnFrom2B(bnDsA, &dsA->b); | |
1723 | BnFrom2B(bnH, curveData->h); | |
1724 | BnFrom2B(bnN, curveData->n); |
1725 BnFrom2B(bnXeB, &QeB->x.b);
1726 pQeB = EccInitPoint2B(group, QeB, context); 1727 pQsB = EccInitPoint2B(group, QsB, context); 1728
1729 // Compute the public ephemeral key pQeA = [de,A]G
1730 if( (retVal = PointMul(group, pQeA, bnDeA, NULL, NULL, context)) 1731 != CRYPT_SUCCESS)
1732 goto Cleanup;
1733
1734 if(EC_POINT_get_affine_coordinates_GFp(group, pQeA, bnXeA, NULL, context) != 1) 1735 FAIL(FATAL_ERROR_INTERNAL);
1736
1737 // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n. 1738 // tA := (ds,A + de,A avf(Xe,A)) mod n (3)
1739 // Compute 'tA' = ('deA' + 'dsA' avf('XeA')) mod n 1740 // Ta = avf(XeA);
1741 BN_copy(bnTa, bnXeA);
1742 avf1(bnTa, bnN);
1743 if(// do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n 1744 !BN_mod_mul(bnTa, bnDsA, bnTa, bnN, context) 1745
1746 // now Ta = deA + Ta mod n = deA + dsA * avf(XeA) mod n 1747 || !BN_mod_add(bnTa, bnDeA, bnTa, bnN, context)
1748 )
1749 FAIL(FATAL_ERROR_INTERNAL);
1750
1751 // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
1752 // Put this in because almost every case of h is == 1 so skip the call when 1753 // not necessary.
1754 if(!BN_is_one(bnH))
1755 {
1756 // Cofactor is not 1 so compute Ta := Ta * h mod n 1757 if(!BN_mul(bnTa, bnTa, bnH, context))
1758 FAIL(FATAL_ERROR_INTERNAL);
1759 }
1760
1761 // Now that 'tA' is (h * 'tA' mod n) 1762 // 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B).
1763
1764 // first, compute XeB = avf(XeB) 1765 avf1(bnXeB, bnN);
1766
1767 // QsB := [XeB]QsB
1768 if( !EC_POINT_mul(group, pQsB, NULL, pQsB, bnXeB, context) 1769
1770 // QeB := QsB + QeB
1771 || !EC_POINT_add(group, pQeB, pQeB, pQsB, context) 1772 )
1773 FAIL(FATAL_ERROR_INTERNAL);
1774
1775 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity 1776 if(PointMul(group, pQeB, NULL, pQeB, bnTa, context) == CRYPT_SUCCESS) 1777 // Convert BIGNUM E to TPM2B E
1778 Point2B(group, outZ, pQeB, (INT16)BN_num_bytes(bnN), context); 1779
1780 Cleanup:
1781 if(pQeA != NULL) EC_POINT_free(pQeA);
1782 if(pQeB != NULL) EC_POINT_free(pQeB);
1783 if(pQsB != NULL) EC_POINT_free(pQsB); 1784 if(group != NULL) EC_GROUP_free(group); 1785 BN_CTX_end(context);
1786 BN_CTX_free(context);
1787
1788 return retVal;
1789
1790 }
1791 #endif // TPM_ALG_ECMQV
1792 #ifdef TPM_ALG_SM2 //%
This function does the associated value computation required by SM2 key exchange. This is different form 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.
1793 static BOOL
1794 avfSm2(
1795 BIGNUM *bnX, // IN/OUT: the reduced value 1796 BIGNUM *bnN // IN: the order of the curve 1797 )
1798 {
1799 // a) set w := ceil(ceil(log2(n)) / 2) - 1
1800 int w = ((BN_num_bits(bnN) + 1) / 2) - 1;
1801
1802 // b) set x' := 2^w + ( x & (2^w - 1))
1803 // This is just like the avf for MQV where x' = 2^w + (x mod 2^w)
1804 BN_mask_bits(bnX, w); // as wiht avf1, this is too big by a factor of 2 but 1805 // it doesn't matter becasue we SET the extra bit anyway 1806 BN_set_bit(bnX, w);
1807 return TRUE;
1808 }
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
Return Value | Meaning |
CRYPT_SUCCESS | results is valid |
CRYPT_NO_RESULT | the value for dsA does not give a valid point on the curve |
1809 | static CRYPT_RESULT | |||
1810 | SM2KeyExchange( | |||
1811 | TPMS_ECC_POINT | *outZ, | // | OUT: the computed point |
1812 | TPM_ECC_CURVE | curveId, | // | IN: the curve for the computations |
1813 | TPM2B_ECC_PARAMETER | *dsA, | // | IN: static private TPM key |
1814 | TPM2B_ECC_PARAMETER | *deA, | // | IN: ephemeral private TPM key |
1815 | TPMS_ECC_POINT | *QsB, | // | IN: static public party B key |
1816 | TPMS_ECC_POINT | *QeB | // | IN: ephemeral public party B key |
1817 | ) | |||
1818 | { | |||
1819 | BN_CTX | *context; | ||
1820 | EC_POINT | *pQeA = NULL; | ||
1821 | EC_POINT | *pQeB = NULL; | ||
1822 | EC_POINT | *pQsB = NULL; | ||
1823 | EC_GROUP | *group = NULL; | ||
1824 | BIGNUM | *bnTa; | ||
1825 | BIGNUM | *bnDeA; | ||
1826 | BIGNUM | *bnDsA; | ||
1827 | BIGNUM | *bnXeA; | // | x coordinate of ephemeral party A key |
1828 | BIGNUM | *bnH; | ||
1829 | BIGNUM | *bnN; | ||
1830 | BIGNUM | *bnXeB; |
1831 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 1832 CRYPT_RESULT retVal;
1833
1834 pAssert( curveData != NULL && outZ != NULL && dsA != NULL 1835 && deA != NULL && QsB != NULL && QeB != NULL);
1836
1837 context = BN_CTX_new();
1838 if(context == NULL || curveData == NULL) 1839 FAIL(FATAL_ERROR_ALLOCATION);
1840 BN_CTX_start(context);
1841 bnTa = BN_CTX_get(context); 1842 bnDeA = BN_CTX_get(context); 1843 bnDsA = BN_CTX_get(context); 1844 bnXeA = BN_CTX_get(context); 1845 bnH = BN_CTX_get(context); 1846 bnN = BN_CTX_get(context); 1847 bnXeB = BN_CTX_get(context); 1848 if(bnXeB == NULL)
1849 FAIL(FATAL_ERROR_ALLOCATION);
1850
1851 // Initialize group parameters and local values of input 1852 if((group = EccCurveInit(curveId, context)) == NULL) 1853 FAIL(FATAL_ERROR_INTERNAL);
1854
1855 if((pQeA = EC_POINT_new(group)) == NULL) 1856 FAIL(FATAL_ERROR_ALLOCATION);
1857
1858 BnFrom2B(bnDeA, &deA->b);
1859 BnFrom2B(bnDsA, &dsA->b);
1860 BnFrom2B(bnH, curveData->h);
1861 BnFrom2B(bnN, curveData->n);
1862 BnFrom2B(bnXeB, &QeB->x.b);
1863 pQeB = EccInitPoint2B(group, QeB, context); 1864 pQsB = EccInitPoint2B(group, QsB, context); 1865
1866 // Compute the public ephemeral key pQeA = [de,A]G
1867 if( (retVal = PointMul(group, pQeA, bnDeA, NULL, NULL, context)) 1868 != CRYPT_SUCCESS)
1869 goto Cleanup;
1870
1871 if(EC_POINT_get_affine_coordinates_GFp(group, pQeA, bnXeA, NULL, context) != 1) 1872 FAIL(FATAL_ERROR_INTERNAL);
1873
1874 // tA := (ds,A + de,A avf(Xe,A)) mod n (3)
1875 // Compute 'tA' = ('dsA' + 'deA' avf('XeA')) mod n 1876 // Ta = avf(XeA);
1877 BN_copy(bnTa, bnXeA);
1878 avfSm2(bnTa, bnN);
1879 if(// do Ta = de,A * Ta mod n = deA * avf(XeA) mod n 1880 !BN_mod_mul(bnTa, bnDeA, bnTa, bnN, context) 1881
1882 // now Ta = dsA + Ta mod n = dsA + deA * avf(XeA) mod n 1883 || !BN_mod_add(bnTa, bnDsA, bnTa, bnN, context)
1884 )
1885 | FAIL(FATAL_ERROR_INTERNAL); | |
1886 | ||
1887 | // | outZ ? [h tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4) |
1888 | // Put this in because almost every case of h is == 1 so skip the call when | |
1889 | // not necessary. | |
1890 | if(!BN_is_one(bnH)) | |
1891 | { | |
1892 | // Cofactor is not 1 so compute Ta := Ta * h mod n | |
1893 | if(!BN_mul(bnTa, bnTa, bnH, context)) | |
1894 | FAIL(FATAL_ERROR_INTERNAL); | |
1895 | } | |
1896 |
1897 // Now that 'tA' is (h * 'tA' mod n)
1898 // 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)).
1899
1900 // first, compute XeB = avf(XeB) 1901 avfSm2(bnXeB, bnN);
1902
1903 // QeB := [XeB]QeB
1904 if( !EC_POINT_mul(group, pQeB, NULL, pQeB, bnXeB, context) 1905
1906 // QeB := QsB + QeB
1907 || !EC_POINT_add(group, pQeB, pQeB, pQsB, context) 1908 )
1909 FAIL(FATAL_ERROR_INTERNAL);
1910
1911 // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity 1912 if(PointMul(group, pQeB, NULL, pQeB, bnTa, context) == CRYPT_SUCCESS) 1913 // Convert BIGNUM E to TPM2B E
1914 Point2B(group, outZ, pQeB, (INT16)BN_num_bytes(bnN), context); 1915
1916 Cleanup:
1917 if(pQeA != NULL) EC_POINT_free(pQeA);
1918 if(pQeB != NULL) EC_POINT_free(pQeB);
1919 if(pQsB != NULL) EC_POINT_free(pQsB); 1920 if(group != NULL) EC_GROUP_free(group); 1921 BN_CTX_end(context);
1922 BN_CTX_free(context);
1923
1924 return retVal;
1925
1926 }
1927 #endif //% TPM_ALG_SM2
This function performs the two phase key exchange defined in SP800-56A, 6.1.1.2 Full Unified Model, C(2, 2, ECC CDH).
1928 static CRYPT_RESULT
1929 C_2_2_ECDH(
1930 TPMS_ECC_POINT *outZ1, // OUT: Zs
1931 TPMS_ECC_POINT *outZ2, // OUT: Ze
1932 TPM_ECC_CURVE curveId, // IN: the curve for the computations 1933 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
1934 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key 1935 TPMS_ECC_POINT *QsB, // IN: static public party B key 1936 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key 1937 )
1938 {
1939 BN_CTX *context;
1940 EC_POINT *pQ = NULL;
1941 EC_GROUP *group = NULL;
1942 BIGNUM *bnD;
1943 INT16 size;
1944 const ECC_CURVE_DATA *curveData = GetCurveData(curveId); 1945
1946 context = BN_CTX_new();
1947 if(context == NULL || curveData == NULL) 1948 FAIL(FATAL_ERROR_ALLOCATION);
1949 BN_CTX_start(context);
1950 if((bnD = BN_CTX_get(context)) == NULL) 1951 FAIL(FATAL_ERROR_INTERNAL);
1952
1953 // Initialize group parameters and local values of input 1954 if((group = EccCurveInit(curveId, context)) == NULL)
1955 | FAIL(FATAL_ERROR_INTERNAL); | ||
1956 | size = (INT16)BN_num_bytes(&group->order); | ||
1957 | |||
1958 | // Get the static private key of A | ||
1959 | BnFrom2B(bnD, &dsA->b); | ||
1960 | |||
1961 | // Initialize the static public point from B | ||
1962 | pQ = EccInitPoint2B(group, QsB, context); | ||
1963 | |||
1964 | // Do the point multiply for the Zs value | ||
1965 | if(PointMul(group, pQ, NULL, pQ, bnD, context) | != CRYPT_NO_RESULT) | |
1966 | // Convert the Zs value | ||
1967 | Point2B(group, outZ1, pQ, size, context); | ||
1968 | |||
1969 | // Get the ephemeral private key of A | ||
1970 | BnFrom2B(bnD, &deA->b); | ||
1971 | |||
1972 | // Initalize the ephemeral public point from B | ||
1973 | PointFrom2B(group, pQ, QeB, context); | ||
1974 | |||
1975 | // Do the point multiply for the Ze value | ||
1976 | if(PointMul(group, pQ, NULL, pQ, bnD, context) | != CRYPT_NO_RESULT) | |
1977 | // Convert the Ze value. | ||
1978 | Point2B(group, outZ2, pQ, size, context); | ||
1979 | |||
1980 | if(pQ != NULL) EC_POINT_free(pQ); | ||
1981 | if(group != NULL) EC_GROUP_free(group); | ||
1982 | BN_CTX_end(context); | ||
1983 | BN_CTX_free(context); | ||
1984 | return CRYPT_SUCCESS; | ||
1985 | } |
This function is the dispatch routine for the EC key exchange function that use two ephemeral and two static keys.
Return Value | Meaning |
CRYPT_SCHEME | scheme is not defined |
1986 LIB_EXPORT CRYPT_RESULT
1987 _cpri C_2_2_KeyExchange(
1988 TPMS_ECC_POINT *outZ1, // OUT: a computed point
1989 TPMS_ECC_POINT *outZ2, // OUT: and optional second point 1990 TPM_ECC_CURVE curveId, // IN: the curve for the computations 1991 TPM_ALG_ID scheme, // IN: the key exchange scheme
1992 TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key 1993 TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key 1994 TPMS_ECC_POINT *QsB, // IN: static public party B key
1995 TPMS_ECC_POINT *QeB // IN: ephemeral public party B key 1996 )
1997 {
1998 pAssert( outZ1 != NULL
1999 && dsA != NULL && deA != NULL
2000 && QsB != NULL && QeB != NULL);
2001
2002 // Initalize the output points so that they are empty until one of the 2003 // functions decides otherwise
2004 outZ1->x.b.size = 0;
2005 outZ1->y.b.size = 0;
2006 if(outZ2 != NULL)
2007 {
2008 outZ2->x.b.size = 0;
2009 outZ2->y.b.size = 0;
2010 }
2011
2012 switch (scheme)
2013 {
2014 case TPM_ALG_ECDH:
2015 return C_2_2_ECDH(outZ1, outZ2, curveId, dsA, deA, QsB, QeB); 2016 break;
2017 #ifdef TPM_ALG_ECMQV
2018 case TPM_ALG_ECMQV:
2019 return C_2_2_MQV(outZ1, curveId, dsA, deA, QsB, QeB);
2020 break;
2021 #endif
2022 #ifdef TPM_ALG_SM2
2023 case TPM_ALG_SM2:
2024 return SM2KeyExchange(outZ1, curveId, dsA, deA, QsB, QeB); 2025 break;
2026 #endif
2027 default:
2028 return CRYPT_SCHEME;
2029 }
2030 }
2031 #else //%
Stub used when the 2-phase key exchange is not defined so that the linker has something to associate with the value in the .def file.
2032 LIB_EXPORT CRYPT_RESULT
2033 _cpri C_2_2_KeyExchange(
2034 void
2035 )
2036 {
2037 return CRYPT_FAIL;
2038 }
2039 #endif //% CC_ZGen_2Phase 2040 #endif // TPM_ALG_ECC
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.
This module simulates the cancel pins on the TPM.
Includes, Typedefs, Structures, and Defines
#include "PlatformData.h"
Check if the cancel flag is set
Return Value | Meaning |
TRUE | if cancel flag is set |
FALSE | if cancel flag is not set |
LIB_EXPORT BOOL
_plat IsCanceled(
void
5 )
6 {
// return cancel flag
return s_isCanceled; 9 }
Set cancel flag.
LIB_EXPORT void
_plat SetCancel(
void
13 )
14 {
s_isCanceled = TRUE;
return; 17 }
Clear cancel flag
LIB_EXPORT void
_plat ClearCancel(
void
21 )
22 {
s_isCanceled = FALSE;
return; 25 }
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.
Includes and Data Definitions
#include <time.h>
#include "PlatformData.h"
#include "Platform.h"
Set the current clock time as initial time. This function is called at a power on event to reset the clock
LIB_EXPORT void
_plat ClockReset(
void
7 )
8 {
// Implementation specific: Microsoft C set CLOCKS_PER_SEC to be 1/1000,
// so here the measurement of clock() is in millisecond.
s_initClock = clock();
s_adjustRate = CLOCK_NOMINAL; 13
14 return; 15 }
Function returns the compensated time from the start of the command when
_plat__ClockTimeFromStart() was called.
unsigned long long
_plat ClockTimeFromStart(
void
19 )
20 {
unsigned long long currentClock = clock();
return ((currentClock - s_initClock) * CLOCK_NOMINAL) / s_adjustRate; 23 }
Get the time elapsed from current to the last time the _plat__ClockTimeElapsed() is called. For the first
_plat__ClockTimeElapsed() call after a power on event, this call report the elapsed time from power on to the current call
LIB_EXPORT unsigned long long
_plat ClockTimeElapsed(
void
27 )
28 {
unsigned long long elapsed;
unsigned long long currentClock = clock();
elapsed = ((currentClock - s_initClock) * CLOCK_NOMINAL) / s_adjustRate;
s_initClock += (elapsed * s_adjustRate) / CLOCK_NOMINAL; 33
#ifdef DEBUGGING_TIME
// Put this in so that TPM time will pass much faster than real time when
// doing debug.
// A value of 1000 for DEBUG_TIME_MULTIPLER will make each ms into a second
// A good value might be 100
elapsed *= DEBUG_TIME_MULTIPLIER
#endif
return elapsed;
42 }
Adjust the clock rate
LIB_EXPORT void
_plat ClockAdjustRate(
int adjust // IN: the adjust number. It could be positive
// or negative
47 )
48 {
// We expect the caller should only use a fixed set of constant values to
// adjust the rate
switch(adjust)
52 {
case CLOCK_ADJUST_COARSE:
s_adjustRate += CLOCK_ADJUST_COARSE;
break;
case -CLOCK_ADJUST_COARSE:
s_adjustRate -= CLOCK_ADJUST_COARSE;
break;
case CLOCK_ADJUST_MEDIUM:
s_adjustRate += CLOCK_ADJUST_MEDIUM;
break;
case -CLOCK_ADJUST_MEDIUM:
s_adjustRate -= CLOCK_ADJUST_MEDIUM;
break;
case CLOCK_ADJUST_FINE:
s_adjustRate += CLOCK_ADJUST_FINE;
break;
case -CLOCK_ADJUST_FINE:
s_adjustRate -= CLOCK_ADJUST_FINE;
break;
default:
// ignore any other values;
break;
74 }
75
if(s_adjustRate > (CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT))
s_adjustRate = CLOCK_NOMINAL + CLOCK_ADJUST_LIMIT;
if(s_adjustRate < (CLOCK_NOMINAL - CLOCK_ADJUST_LIMIT))
s_adjustRate = CLOCK_NOMINAL-CLOCK_ADJUST_LIMIT; 80
81 return; 82 }
#define _CRT_RAND_S
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include "TpmBuildSwitches.h"
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.”
6 | extern | uint32_t | lastEntropy; |
7 | extern | int | firstValue; |
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. If the caller does not ask for any entropy, then this is a startup indication and firstValue should be reset.
Return Value | Meaning |
< 0 | hardware failure of the entropy generator, this is sticky |
>= 0 | the returned amount of entropy (bytes) |
LIB_EXPORT int32_t
_plat GetEntropy(
unsigned char *entropy, // output buffer
uint32_t amount // amount requested 12 )
13 {
uint32_t rndNum;
int OK = 1; 16
17 if(amount == 0)
18 {
firstValue = 1;
return 0;
21 }
22
// Only provide entropy 32 bits at a time to test the ability
// of the caller to deal with partial results.
OK = rand_s(&rndNum) == 0;
if(OK)
27 {
if(firstValue)
firstValue = 0;
else
OK = (rndNum != lastEntropy); 32 }
33 | if(OK) | |
34 | { | |
35 | lastEntropy = rndNum; | |
36 | if(amount > sizeof(rndNum)) | |
37 | amount = sizeof(rndNum); | |
38 | memcpy(entropy, &rndNum, amount); | |
39 | } | |
40 | return (OK) ? (int32_t)amount : -1; | |
41 | } |
#include "PlatformData.h"
#include "TpmError.h"
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.
LIB_EXPORT unsigned char
_plat LocalityGet(
void
6 )
7 {
8 return s_locality; 9 }
Set the most recent command locality in locality value form
LIB_EXPORT void
_plat LocalitySet(
unsigned char locality
13 )
14 {
if(locality > 4 && locality < 32)
locality = 0;
s_locality = locality;
return; 19 }
_plat__IsRsaKeyCacheEnabled()
This function is used to check if the RSA key cache is enabled or not.
LIB_EXPORT int
_plat IsRsaKeyCacheEnabled(
void
23 )
24 {
25 return s_RsaKeyCacheEnabled; 26 }
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.
#include <memory.h>
#include <string.h>
#include "PlatformData.h"
#include "TpmError.h"
#include "assert.h"
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
LIB_EXPORT void
_plat NvErrors(
BOOL recoverable,
BOOL unrecoverable 10 )
11 {
s_NV_unrecoverable = unrecoverable;
s_NV_recoverable = recoverable; 14 }
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.
Return Value | Meaning |
0 | if success |
> 0 | if receive recoverable error |
<0 | if unrecoverable error |
LIB_EXPORT int
_plat NVEnable(
void *platParameter // IN: platform specific parameter 18 )
19 {
20 | (platParameter); | // to keep compiler quiet | |
21 | // Start assuming everything is | OK |
s_NV_unrecoverable = FALSE;
s_NV_recoverable = FALSE; 24
25 #ifdef FILE_BACKED_NV 26
27 if(s_NVFile != NULL) return 0; 28
// Try to open an exist NVChip file for read/write
if(0 != fopen_s(&s_NVFile, "NVChip", "r+b"))
s_NVFile = NULL; 32
33 if(NULL != s_NVFile)
34 {
// See if the NVChip file is empty
fseek(s_NVFile, 0, SEEK_END);
if(0 == ftell(s_NVFile))
s_NVFile = NULL; 39 }
40
41 if(s_NVFile == NULL)
42 {
// Initialize all the byte in the new file to 0
memset(s_NV, 0, NV_MEMORY_SIZE); 45
// If NVChip file does not exist, try to create it for read/write
fopen_s(&s_NVFile, "NVChip", "w+b");
// Start initialize at the end of new file
fseek(s_NVFile, 0, SEEK_END);
// Write 0s to NVChip file
fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); 52 }
53 else
54 {
// If NVChip file exist, assume the size is correct
fseek(s_NVFile, 0, SEEK_END);
assert(ftell(s_NVFile) == NV_MEMORY_SIZE);
// read NV file data to memory
fseek(s_NVFile, 0, SEEK_SET);
fread(s_NV, NV_MEMORY_SIZE, 1, s_NVFile); 61 }
#endif
// NV contents have been read and the error checks have been performed. For
// simulation purposes, use the signaling interface to indicate if an error is
// to be simulated and the type of the error.
if(s_NV_unrecoverable)
return -1;
return s_NV_recoverable; 69 }
Disable NV memory
LIB_EXPORT void
_plat NVDisable(
void
73 )
74 {
75 #ifdef FILE_BACKED_NV 76
assert(s_NVFile != NULL);
// Close NV file
fclose(s_NVFile);
// Set file handle to NULL
s_NVFile = NULL; 82
83 #endif 84
85 return; 86 }
Check if NV is available
Return Value | Meaning |
0 | NV is available |
1 | NV is not available due to write failure |
2 | NV is not available due to rate limit |
LIB_EXPORT int
_plat IsNvAvailable(
void
90 )
91 {
// NV is not available if the TPM is in failure mode
if(!s_NvIsAvailable)
return 1;
95
#ifdef FILE_BACKED_NV
if(s_NVFile == NULL)
return 1;
#endif 100
101 return 0; 102
103 }
Function: Read a chunk of NV memory
LIB_EXPORT void
_plat NvMemoryRead(
unsigned int startOffset, // IN: read start
unsigned int size, // IN: size of bytes to read
void *data // OUT: data buffer
109 )
110 {
111 assert(startOffset + size <= NV_MEMORY_SIZE); 112
// Copy data from RAM
memcpy(data, &s_NV[startOffset], size);
return;
116 }
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.
Return Value | Meaning |
TRUE | the NV location is different from the test value |
FALSE | the NV location is the same as the test value |
LIB_EXPORT BOOL
_plat NvIsDifferent(
unsigned int startOffset, // IN: read start
unsigned int size, // IN: size of bytes to read
void *data // IN: data buffer
122 )
123 {
124 return (memcmp(&s_NV[startOffset], data, size) != 0);
125 }
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.
LIB_EXPORT void
_plat NvMemoryWrite(
unsigned int startOffset, // IN: write start
unsigned int size, // IN: size of bytes to write
void *data // OUT: data buffer
131 )
132 {
133 assert(startOffset + size <= NV_MEMORY_SIZE); 134
// Copy the data to the NV image
memcpy(&s_NV[startOffset], data, size);
137 }
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
LIB_EXPORT void
_plat NvMemoryMove(
unsigned int sourceOffset, // IN: source offset
unsigned int destOffset, // IN: destination offset
unsigned int size // IN: size of data being moved
143 )
144 {
assert(sourceOffset + size <= NV_MEMORY_SIZE);
assert(destOffset + size <= NV_MEMORY_SIZE); 147
// Move data in RAM
memmove(&s_NV[destOffset], &s_NV[sourceOffset], size); 150
151 return;
152 }
Update NV chip
Return Value | Meaning |
0 | NV write success |
non-0 | NV write fail |
153 | LIB_EXPORT int | |
154 | _plat NvCommit( | |
155 | void | |
156 | ) | |
157 | { | |
158 | #ifdef FILE_BACKED_NV | |
159 | // If NV file is not available, return failure | |
160 | if(s_NVFile == NULL) | |
161 | return 1; | |
162 | ||
163 | // Write RAM data to NV | |
164 | fseek(s_NVFile, 0, SEEK_SET); | |
165 | fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); | |
166 | return 0; | |
167 | #else | |
168 | return 0; | |
169 | #endif | |
170 | ||
171 | } | |
Set the current NV state to available. This function is for testing purpose only. | It is not part of the | |
platform NV logic | ||
172 | LIB_EXPORT void | |
173 | _plat SetNvAvail( | |
174 | void | |
175 | ) | |
176 | { | |
177 | s_NvIsAvailable = TRUE; | |
178 | return; | |
179 | } | |
Set the current NV state to unavailable. This function is for testing purpose only. | It is not part of the | |
platform NV logic | ||
180 | LIB_EXPORT void | |
181 | _plat ClearNvAvail( | |
182 | void | |
183 | ) | |
184 | { | |
185 | s_NvIsAvailable = FALSE; | |
186 | return; | |
187 | } |
Includes and Function Prototypes
1 | #include | "PlatformData.h" |
2 | #include | "Platform.h" |
Signal platform power on
LIB_EXPORT int
_plat Signal_PowerOn(
void
6 )
7 {
// Start clock
_plat ClockReset(); 10
// Initialize locality
s_locality = 0; 13
// Command cancel
s_isCanceled = FALSE; 16
// Need to indicate that we lost power
s_powerLost = TRUE; 19
20 return 0; 21 }
Test whether power was lost before a _TPM_Init()
LIB_EXPORT BOOL
_plat WasPowerLost(
BOOL clear
25 )
26 {
BOOL retVal = s_powerLost;
if(clear)
s_powerLost = FALSE;
return retVal; 31 }
This a TPM reset without a power loss.
LIB_EXPORT int
_plat Signal_Reset(
void
35 )
36 {
// Need to reset the clock
_plat ClockReset();
39
// if we are doing reset but did not have a power failure, then we should
// not need to reload NV ...
return 0; 43 }
Signal platform power off
LIB_EXPORT void
_plat Signal_PowerOff(
void
47 )
48 {
// Prepare NV memory for power off
_plat NVDisable(); 51
52 return; 53 }
1 | #ifndef | PLATFORM_H |
2 | #define | PLATFORM_H |
#include "bool.h"
#include "stdint.h"
#include "TpmError.h"
#include "TpmBuildSwitches.h"
#define UNREFERENCED(a) ((void)(a))
Signal power on This signal is simulate by a RPC call
LIB_EXPORT int
_plat Signal_PowerOn(void);
Signal reset This signal is simulate by a RPC call
LIB_EXPORT int
_plat Signal_Reset(void);
Indicates if the power was lost before a _TPM__Init().
LIB_EXPORT BOOL
_plat WasPowerLost(BOOL clear);
Signal power off This signal is simulate by a RPC call
LIB_EXPORT void
_plat Signal_PowerOff(void);
_plat__PhysicalPresenceAsserted()
Check if physical presence is signaled
Return Value | Meaning |
TRUE | if physical presence is signaled |
FALSE | if physical presence is not signaled |
LIB_EXPORT BOOL
_plat PhysicalPresenceAsserted(void);
_plat__Signal_PhysicalPresenceOn
Signal physical presence on This signal is simulate by a RPC call
LIB_EXPORT void
_plat Signal_PhysicalPresenceOn(void);
_plat__Signal_PhysicalPresenceOff()
Signal physical presence off This signal is simulate by a RPC call
LIB_EXPORT void
_plat Signal_PhysicalPresenceOff(void);
Check if the cancel flag is set
Return Value | Meaning |
TRUE | if cancel flag is set |
FALSE | if cancel flag is not set |
LIB_EXPORT BOOL
_plat IsCanceled(void);
Set cancel flag.
LIB_EXPORT void
_plat SetCancel(void);
Clear cancel flag
LIB_EXPORT void
_plat ClearCancel( void);
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
LIB_EXPORT void
_plat NvErrors(
BOOL recoverable,
BOOL unrecoverable
32 );
Enable platform NV memory NV memory is automatically enabled at power on event. This function is mostly for TPM_Manufacture() to access NV memory without a power on event
Return Value | Meaning |
0 | if success |
non-0 | if fail |
LIB_EXPORT int
_plat NVEnable(
void *platParameter // IN: platform specific parameters 36 );
Disable platform NV memory NV memory is automatically disabled at power off event. This function is mostly for TPM_Manufacture() to disable NV memory without a power off event
LIB_EXPORT void
_plat NVDisable(void);
Check if NV is available
Return Value | Meaning |
0 | NV is available |
1 | NV is not available due to write failure |
2 | NV is not available due to rate limit |
LIB_EXPORT int
_plat IsNvAvailable(void);
Update NV chip
Return Value | Meaning |
0 | NV write success |
non-0 | NV write fail |
LIB_EXPORT int
_plat NvCommit(void);
Read a chunk of NV memory
LIB_EXPORT void
_plat NvMemoryRead(
unsigned int startOffset, // IN: read start
unsigned int size, // IN: size of bytes to read
void *data // OUT: data buffer 48 );
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.
Return Value | Meaning |
TRUE | the NV location is different from the test value |
FALSE | the NV location is the same as the test value |
LIB_EXPORT BOOL
_plat NvIsDifferent(
unsigned int startOffset, // IN: read start
unsigned int size, // IN: size of bytes to compare
void *data // IN: data buffer 54 );
Write a chunk of NV memory
LIB_EXPORT void
_plat NvMemoryWrite(
unsigned int startOffset, // IN: read start
unsigned int size, // IN: size of bytes to read
void *data // OUT: data buffer 60 );
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
LIB_EXPORT void
_plat NvMemoryMove(
unsigned int sourceOffset, // IN: source offset
unsigned int destOffset, // IN: destination offset
unsigned int size // IN: size of data being moved
66 );
Set the current NV state to available. This function is for testing purposes only. It is not part of the platform NV logic
LIB_EXPORT void
_plat SetNvAvail(void);
Set the current NV state to unavailable. This function is for testing purposes only. It is not part of the platform NV logic
LIB_EXPORT void
_plat ClearNvAvail(void);
Get the most recent command locality in locality value form
LIB_EXPORT unsigned char
_plat LocalityGet(void);
Set the most recent command locality in locality value form
LIB_EXPORT void
_plat LocalitySet(
unsigned char locality 76 );
This function is used to check if the RSA key cache is enabled or not.
LIB_EXPORT int
_plat IsRsaKeyCacheEnabled(
void
80 );
C.8.7. Clock Constants and Functions
Assume that the nominal divisor is 30000
#define CLOCK_NOMINAL 30000
A 1% change in rate is 300 counts
#define CLOCK_ADJUST_COARSE 300
A .1 change in rate is 30 counts
#define CLOCK_ADJUST_MEDIUM 30
A minimum change in rate is 1 count
#define CLOCK_ADJUST_FINE 1
The clock tolerance is +/-15% (4500 counts) Allow some guard band (16.7%)
#define CLOCK_ADJUST_LIMIT 5000
This function sets the current clock time as initial time. This function is called at a power on event to reset the clock
LIB_EXPORT void
_plat ClockReset(void);
Function returns the compensated time from the start of the command when
_plat__ClockTimeFromStart() was called.
LIB_EXPORT unsigned long long
_plat ClockTimeFromStart(
void
91 );
Get the time elapsed from current to the last time the _plat__ClockTimeElapsed() is called. For the first
_plat__ClockTimeElapsed() call after a power on event, this call report the elapsed time from power on to the current call
LIB_EXPORT unsigned long long
_plat ClockTimeElapsed(void);
Adjust the clock rate
LIB_EXPORT void
_plat ClockAdjustRate(
int adjust // IN: the adjust number. It could be
// positive or negative
98 );
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. If the caller does not ask for any entropy, then this is a startup indication and firstValue should be reset.
Return Value | Meaning |
< 0 | hardware failure of the entropy generator, this is sticky |
>= 0 | the returned amount of entropy (bytes) |
99 | LIB_EXPORT int32_t | ||
100 | _plat GetEntropy( | ||
101 | unsigned char | *entropy, | // output buffer |
102 | uint32_t | amount | // amount requested |
103 | ); | ||
104 | #endif |
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.
#ifndef _PLATFORM_DATA_H_
#define _PLATFORM_DATA_H_
#include "TpmBuildSwitches.h"
#include "Implementation.h"
#include "bool.h"
From Cancel.c Cancel flag. It is initialized as FALSE, which indicate the command is not being canceled
extern BOOL s_isCanceled;
From Clock.c This variable records the time when _plat__ClockReset() is called. This mechanism allow us to subtract the time when TPM is power off from the total time reported by clock() function
extern unsigned long long s_initClock;
extern unsigned int s_adjustRate;
From LocalityPlat.c Locality of current command
extern unsigned char s_locality;
From NVMem.c Choose if the NV memory should be backed by RAM or by file. If this macro is defined, then a file is used as NV. If it is not defined, then RAM is used to back NV memory. Comment out to use RAM.
#define FILE_BACKED_NV
#if defined FILE_BACKED_NV
#include <stdio.h>
A file to emulate NV storage
extern FILE* s_NVFile;
#endif
extern unsigned char s_NV[NV_MEMORY_SIZE];
extern BOOL s_NvIsAvailable;
extern BOOL s_NV_unrecoverable;
extern BOOL s_NV_recoverable;
From PPPlat.c Physical presence. It is initialized to FALSE
extern BOOL s_physicalPresence;
From Power
extern BOOL s_powerLost;
From Entropy.c
extern uint32_t lastEntropy;
extern int firstValue;
23 #endif // _PLATFORM_DATA_H_
This file will instance the TPM variables that are not stack allocated. The descriptions for these variables is in Global.h for this project.
This include is required to set the NV memory size consistently across all parts of the implementation.
#include "Implementation.h"
#include "Platform.h"
#include "PlatformData.h"
From Cancel.c
BOOL s_isCanceled;
From Clock.c
unsigned long long s_initClock;
unsigned int s_adjustRate;
From LocalityPlat.c
unsigned char s_locality;
From Power.c
BOOL s_powerLost;
From Entropy.c
uint32_t lastEntropy;
int firstValue;
From NVMem.c
#ifdef VTPM
# undef FILE_BACKED_NV
#endif
#ifdef FILE_BACKED_NV
FILE *s_NVFile = NULL;
16 | #endif | ||
17 | unsigned | char | s_NV[NV_MEMORY_SIZE]; |
18 | BOOL | s_NvIsAvailable; | |
19 | BOOL | s_NV_unrecoverable; | |
20 | BOOL | s_NV_recoverable; |
From PPPlat.c
21 BOOL s_physicalPresence;
This module simulates the physical present interface pins on the TPM.
#include "PlatformData.h"
_plat__PhysicalPresenceAsserted()
Check if physical presence is signaled
Return Value | Meaning |
TRUE | if physical presence is signaled |
FALSE | if physical presence is not signaled |
LIB_EXPORT BOOL
_plat PhysicalPresenceAsserted(
void
5 )
6 {
// Do not know how to check physical presence without real hardware.
// so always return TRUE;
return s_physicalPresence; 10 }
_plat__Signal_PhysicalPresenceOn()
Signal physical presence on
LIB_EXPORT void
_plat Signal_PhysicalPresenceOn(
void
14 )
15 {
s_physicalPresence = TRUE;
return; 18 }
_plat__Signal_PhysicalPresenceOff()
Signal physical presence off
LIB_EXPORT void
_plat Signal_PhysicalPresenceOff(
void
22 )
23 {
s_physicalPresence = FALSE;
return; 26 }
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.
#include "stdint.h"
#include "TpmBuildSwitches.h"
const char notReallyUnique[] =
"This is not really a unique value. A real unique value should"
" be generated by the platform.";
This function is used to access the platform-specific unique value. This function places the unique value in the provided buffer (b) and returns the number of bytes transferred. The function will not copy more data than bSize.
NOTE: If a platform unique value has unequal distribution of uniqueness and bSize is smaller than the size of the unique value, the bSize portion with the most uniqueness should be returned.
LIB_EXPORT uint32_t
_plat GetUnique(
uint32_t which, // authorities (0) or details
uint32_t bSize, // size of the buffer
unsigned char *b // output buffer 11 )
12 {
const char *from = notReallyUnique;
uint32_t retVal = 0; 15
16 if(which == 0) // the authorities value 17 {
for(retVal = 0;
*from != 0 && retVal < bSize;
retVal++)
21 {
22 *b++ = *from++; 23 }
24 }
25 else
26 {
#define uSize sizeof(notReallyUnique)
b = &b[((bSize < uSize) ? bSize : uSize) - 1];
for(retVal = 0;
*from != 0 && retVal < bSize;
retVal++)
32 {
33 *b-- = *from++; 34 }
35 }
36 return retVal; 37 }
These files provide an RPC interface for a TPM simulation.
The simulation uses two ports: a command port and a hardware simulation port. Only TPM commands defined in TPM 2.0 Part 3 are sent to the TPM on the command port. The hardware simulation port is used to simulate hardware events such as power on/off and locality; and indications such as
_TPM_HashStart.
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 complete 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 |
TPM Commands. All commands acknowledge processing by returning a UINT32 == 0 except where noted
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_SESSION_END 20 |
24 | #define | TPM_STOP 21 |
25 | #define | TPM_GET_COMMAND_RESPONSE_SIZES 25 |
26 | #define | TPM_TEST_FAILURE_MODE 30 |
27 enum TpmEndPointInfo
28 {
tpmPlatformAvailable = 0x01,
tpmUsesTbs = 0x02,
tpmInRawMode = 0x04,
tpmSupportsPP = 0x08
33 };
34
// Existing RPC interface type definitions retained so that the implementation
// can be re-used
typedef struct
38 {
unsigned long BufferSize;
unsigned char *Buffer;
} _IN_BUFFER;
42
43 typedef unsigned char *_OUTPUT_BUFFER;
44
45 typedef struct
46 {
uint32_t BufferSize;
_OUTPUT_BUFFER Buffer;
} _OUT_BUFFER;
50
//** TPM Command Function Prototypes
void _rpc Signal_PowerOn(BOOL isReset);
void _rpc Signal_PowerOff();
void _rpc ForceFailureMode();
void _rpc Signal_PhysicalPresenceOn();
void _rpc Signal_PhysicalPresenceOff();
void _rpc Signal_Hash_Start();
void _rpc Signal_Hash_Data(
_IN_BUFFER input 60 );
void _rpc Signal_HashEnd();
void _rpc Send_Command(
unsigned char locality,
_IN_BUFFER request,
_OUT_BUFFER *response 66 );
void _rpc Signal_CancelOn();
void _rpc Signal_CancelOff();
void _rpc Signal_NvOn();
void _rpc Signal_NvOff();
BOOL _rpc InjectEPS(
const char* seed,
int seedSize 74 );
start the TPM server on the indicated socket. The TPM is single-threaded and will accept connections first-come-first-served. Once a connection is dropped another client can connect.
BOOL TpmServer(SOCKET ServerSocket);
#endif
This file contains the socket interface to a TPM simulator.
Includes, Locals, Defines and Function Prototypes
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#include "string.h"
#include <stdlib.h>
#include <stdint.h>
#include "TpmTcpProtocol.h"
BOOL ReadBytes(SOCKET s, char* buffer, int NumBytes);
BOOL ReadVarBytes(SOCKET s, char* buffer, UINT32* BytesReceived, int MaxLen);
BOOL WriteVarBytes(SOCKET s, char *buffer, int BytesToSend);
BOOL WriteBytes(SOCKET s, char* buffer, int NumBytes);
BOOL WriteUINT32(SOCKET s, UINT32 val);
#ifndef IGNORE_STATE
static UINT32 ServerVersion = 1;
#define MAX_BUFFER 1048576
char InputBuffer[MAX_BUFFER]; //The input data buffer for the simulator.
char OutputBuffer[MAX_BUFFER]; //The output data buffer for the simulator.
struct {
UINT32 largestCommandSize;
UINT32 largestCommand;
UINT32 largestResponseSize;
UINT32 largestResponse;
} CommandResponseSizes = {0};
#endif // IGNORE_STATE
This function creates a socket listening on PortNumber.
static int
CreateSocket(
int PortNumber,
SOCKET *listenSocket 29 )
30 {
WSADATA wsaData;
struct sockaddr_in MyAddress; 33
34 int res; 35
// Initialize Winsock
res = WSAStartup(MAKEWORD(2,2), &wsaData);
if (res != 0)
39 {
printf("WSAStartup failed with error: %d\n", res);
return -1; 42 }
43
// create listening socket
*listenSocket = socket(PF_INET, SOCK_STREAM, 0);
if(INVALID_SOCKET == *listenSocket) 47 {
printf("Cannot create server listen socket. Error is 0x%x\n",
WSAGetLastError());
return -1; 51 }
52
// bind the listening socket to the specified port
ZeroMemory(&MyAddress, sizeof(MyAddress));
MyAddress.sin_port=htons((short) PortNumber);
MyAddress.sin_family=AF_INET; 57
res= bind(*listenSocket,(struct sockaddr*) &MyAddress,sizeof(MyAddress));
if(res==SOCKET_ERROR)
60 {
printf("Bind error. Error is 0x%x\n", WSAGetLastError());
return -1; 63 };
64
// listen/wait for server connections
res= listen(*listenSocket,3);
if(res==SOCKET_ERROR)
68 {
printf("Listen error. Error is 0x%x\n", WSAGetLastError());
return -1; 71 };
72
73 return 0; 74 }
This function processes incoming platform requests.
BOOL
PlatformServer(
SOCKET s
78 )
79 {
BOOL ok = TRUE;
UINT32 length = 0;
UINT32 Command; 83
84 for(;;)
85 {
ok = ReadBytes(s, (char*) &Command, 4);
// client disconnected (or other error). We stop processing this client
// and return to our caller who can stop the server or listen for another
// connection.
if(!ok) return TRUE;
Command = ntohl(Command);
switch(Command)
93 {
case TPM_SIGNAL_POWER_ON:
_rpc Signal_PowerOn(FALSE);
break;
97
case TPM_SIGNAL_POWER_OFF:
_rpc Signal_PowerOff();
break;
101
case TPM_SIGNAL_RESET:
_rpc Signal_PowerOn(TRUE);
break;
105 | |||
106 | case TPM_SIGNAL_PHYS_PRES_ON: | ||
107 | _rpc Signal_PhysicalPresenceOn(); | ||
108 | break; | ||
109 | |||
110 | case TPM_SIGNAL_PHYS_PRES_OFF: | ||
111 | _rpc Signal_PhysicalPresenceOff(); | ||
112 | break; | ||
113 | |||
114 | case TPM_SIGNAL_CANCEL_ON: | ||
115 | _rpc Signal_CancelOn(); | ||
116 | break; | ||
117 | |||
118 | case TPM_SIGNAL_CANCEL_OFF: | ||
119 | _rpc Signal_CancelOff(); | ||
120 | break; | ||
121 | |||
122 | case TPM_SIGNAL_NV_ON: | ||
123 | _rpc Signal_NvOn(); | ||
124 | break; | ||
125 | |||
126 | case TPM_SIGNAL_NV_OFF: | ||
127 | _rpc Signal_NvOff(); | ||
128 | break; | ||
129 | |||
130 | case TPM_SESSION_END: | ||
131 | // Client signaled end-of-session | ||
132 | return TRUE; | ||
133 | |||
134 | case TPM_STOP: | ||
135 | // Client requested the simulator to | exit | |
136 | return FALSE; | ||
137 | |||
138 | case TPM_TEST_FAILURE_MODE: | ||
139 | _rpc ForceFailureMode(); | ||
140 | break; | ||
141 | |||
142 | case TPM_GET_COMMAND_RESPONSE_SIZES: | ||
143 | ok = WriteVarBytes(s, (char *)&CommandResponseSizes, | ||
144 | sizeof(CommandResponseSizes)); | ||
145 | memset(&CommandResponseSizes, 0, sizeof(CommandResponseSizes)); | ||
146 | if(!ok) | ||
147 | return TRUE; | ||
148 | break; | ||
149 | |||
150 | default: | ||
151 | printf("Unrecognized platform interface command %d\n", Command); | ||
152 | WriteUINT32(s, 1); | ||
153 | return TRUE; | ||
154 | } | ||
155 | WriteUINT32(s,0); | ||
156 | } | ||
157 | return FALSE; | ||
158 | } |
This function is called to set up the socket interfaces to listen for commands.
DWORD WINAPI
PlatformSvcRoutine(
LPVOID port
162 )
163 {
164 | int PortNumber = (int)(INT_PTR) port; | |
165 | SOCKET listenSocket, serverSocket; | |
166 | struct sockaddr_in HerAddress; | |
167 | int res; | |
168 | int length; | |
169 | BOOL continueServing; | |
170 | ||
171 | res = CreateSocket(PortNumber, &listenSocket); | |
172 | if(res != 0) | |
173 | { | |
174 | printf("Create platform service socket fail\n"); | |
175 | return res; | |
176 | } | |
177 | ||
178 | // Loop accepting connections one-by-one until we are killed or asked to stop | |
179 | // Note the platform service is single-threaded so we don't listen for a new | |
180 | // connection until the prior connection drops. | |
181 | do | |
182 | { | |
183 | printf("Platform server listening on port %d\n", PortNumber); | |
184 | ||
185 | // blocking accept | |
186 | length = sizeof(HerAddress); | |
187 | serverSocket = accept(listenSocket, | |
188 | (struct sockaddr*) &HerAddress, | |
189 | &length); | |
190 | if(serverSocket == SOCKET_ERROR) | |
191 | { | |
192 | printf("Accept error. Error is 0x%x\n", WSAGetLastError()); | |
193 | return -1; | |
194 | }; | |
195 | printf("Client accepted\n"); | |
196 | ||
197 | // normal behavior on client disconnection is to wait for a new client | |
198 | // to connect | |
199 | continueServing = PlatformServer(serverSocket); | |
200 | closesocket(serverSocket); | |
201 | } | |
202 | while(continueServing); | |
203 | ||
204 | return 0; | |
205 | } |
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.
int
PlatformSignalService(
208 | int PortNumber | |
209 | ) | |
210 | { | |
211 | HANDLE hPlatformSvc; | |
212 | int ThreadId; | |
213 | int port = PortNumber; | |
214 | ||
215 | // Create service thread for platform signals | |
216 | hPlatformSvc = CreateThread(NULL, 0, | |
217 | (LPTHREAD_START_ROUTINE)PlatformSvcRoutine, | |
218 | (LPVOID) (INT_PTR) port, 0, (LPDWORD)&ThreadId); | |
219 | if(hPlatformSvc == NULL) | |
220 | { | |
221 | printf("Thread Creation failed\n"); |
222 | return -1; | |
223 | } | |
224 | ||
225 | return 0; | |
226 | } |
This funciton services regular commands.
int
RegularCommandService(
int PortNumber
230 | ) | |
231 | { | |
232 | SOCKET listenSocket; | |
233 | SOCKET serverSocket; | |
234 | struct sockaddr_in HerAddress; | |
235 | ||
236 | int res, length; | |
237 | BOOL continueServing; | |
238 | ||
239 | res = CreateSocket(PortNumber, &listenSocket); | |
240 | if(res != 0) | |
241 | { | |
242 | printf("Create platform service socket fail\n"); | |
243 | return res; | |
244 | } | |
245 | ||
246 | // Loop accepting connections one-by-one until we are killed or asked to stop | |
247 | // Note the TPM command service is single-threaded so we don't listen for | |
248 | // a new connection until the prior connection drops. | |
249 | do | |
250 | { | |
251 | printf("TPM command server listening on port %d\n", PortNumber); | |
252 | ||
253 | // blocking accept | |
254 | length = sizeof(HerAddress); | |
255 | serverSocket = accept(listenSocket, | |
256 | (struct sockaddr*) &HerAddress, | |
257 | &length); | |
258 | if(serverSocket ==SOCKET_ERROR) | |
259 | { | |
260 | printf("Accept error. Error is 0x%x\n", WSAGetLastError()); | |
261 | return -1; | |
262 | }; | |
263 | printf("Client accepted\n"); | |
264 | ||
265 | // normal behavior on client disconnection is to wait for a new client | |
266 | // to connect | |
267 | continueServing = TpmServer(serverSocket); | |
268 | closesocket(serverSocket); | |
269 | } | |
270 | while(continueServing); | |
271 | ||
272 | return 0; | |
273 | } |
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.
int
StartTcpServer(
int PortNumber
277 )
278 {
279 int res;
280
// Start Platform Signal Processing Service
res = PlatformSignalService(PortNumber+1);
if (res != 0)
284 {
printf("PlatformSignalService failed\n");
return res;
287 }
288
// Start Regular/DRTM TPM command service
res = RegularCommandService(PortNumber);
if (res != 0)
292 {
printf("RegularCommandService failed\n");
return res;
295 }
296
297 return 0;
298 }
This function reads the indicated number of bytes (NumBytes) into buffer from the indicated socket.
BOOL
ReadBytes(
SOCKET s,
302 | char *buffer, | |
303 | int NumBytes | |
304 | ) | |
305 | { | |
306 | int res; | |
307 | int numGot = 0; | |
308 | ||
309 | while(numGot<NumBytes) | |
310 | { | |
311 | res = recv(s, buffer+numGot, NumBytes-numGot, 0); | |
312 | if(res == -1) | |
313 | { | |
314 | printf("Receive error. Error is 0x%x\n", WSAGetLastError()); | |
315 | return FALSE; | |
316 | } | |
317 | if(res==0) | |
318 | { | |
319 | return FALSE; | |
320 | } | |
321 | numGot+=res; | |
322 | } | |
323 | return TRUE; | |
324 | } |
This function will send the indicated number of bytes (NumBytes) to the indicated socket
BOOL
WriteBytes(
327 | SOCKET s, |
328 | char *buffer, |
329 | int NumBytes |
330 | ) |
331 | { |
332 | int res; |
333 | int numSent = 0; |
334 | while(numSent<NumBytes) |
335 | { |
336 | res = send(s, buffer+numSent, NumBytes-numSent, 0); |
337 | if(res == -1) |
338 | { |
339 | if(WSAGetLastError() == 0x2745) |
340 | { |
341 | printf("Client disconnected\n"); |
342 | } |
343 | else |
344 | { |
345 | printf("Send error. Error is 0x%x\n", WSAGetLastError()); |
346 | } |
347 | return FALSE; |
348 | } |
349 | numSent+=res; |
350 | } |
351 | return TRUE; |
352 | } |
Send 4 bytes containing hton(1) | |
353 | BOOL |
354 | WriteUINT32( |
355 | SOCKET s, |
356 | UINT32 val |
357 | ) |
358 | { |
359 | UINT32 netVal = htonl(val); |
360 | return WriteBytes(s, (char*) &netVal, 4); |
361 | } |
Get a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big- | |
endian). | |
362 | BOOL |
363 | ReadVarBytes( |
364 | SOCKET s, |
365 | char *buffer, |
366 | UINT32 *BytesReceived, |
367 | int MaxLen |
368 | ) |
369 | { |
370 | int length; |
371 | BOOL res; |
372 | |
373 | res = ReadBytes(s, (char*) &length, 4); |
374 | if(!res) return res; |
375 | length = ntohl(length); |
376 | *BytesReceived = length; |
377 | if(length>MaxLen) |
378 | { |
printf("Buffer too big. Client says %d\n", length);
return FALSE;
381 }
if(length==0) return TRUE;
res = ReadBytes(s, buffer, length);
if(!res) return res;
return TRUE;
386 }
Send a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte order (big- endian).
BOOL
WriteVarBytes(
SOCKET s,
char *buffer,
int BytesToSend
392 )
393 {
UINT32 netLength = htonl(BytesToSend);
BOOL res; 396
res = WriteBytes(s, (char*) &netLength, 4);
if(!res) return res;
res = WriteBytes(s, buffer, BytesToSend);
if(!res) return res;
return TRUE;
402 }
Processing incoming TPM command requests using the protocol / interface defined above.
403 BOOL
404 TpmServer(
405 SOCKET s
406 )
407 {
UINT32 length;
UINT32 Command;
BYTE locality;
BOOL ok;
int result;
int clientVersion;
_IN_BUFFER InBuffer;
_OUT_BUFFER OutBuffer; 416
417 for(;;)
418 {
ok = ReadBytes(s, (char*) &Command, 4);
// client disconnected (or other error). We stop processing this client
// and return to our caller who can stop the server or listen for another
// connection.
if(!ok)
return TRUE;
Command = ntohl(Command);
switch(Command)
427 {
428 case TPM_SIGNAL_HASH_START:
429 _rpc Signal_Hash_Start();
430 break;
431
432 case TPM_SIGNAL_HASH_END:
433 _rpc Signal_HashEnd();
434 break;
435
case TPM_SIGNAL_HASH_DATA:
ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
if(!ok) return TRUE;
InBuffer.Buffer = (BYTE*) InputBuffer;
InBuffer.BufferSize = length;
_rpc Signal_Hash_Data(InBuffer);
break;
443
444 case TPM_SEND_COMMAND:
445 ok = ReadBytes(s, (char*) &locality, 1);
446 if(!ok)
447 return TRUE;
448
ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER);
if(!ok)
return TRUE;
InBuffer.Buffer = (BYTE*) InputBuffer;
InBuffer.BufferSize = length;
OutBuffer.BufferSize = MAX_BUFFER;
OutBuffer.Buffer = (_OUTPUT_BUFFER) OutputBuffer;
// record the number of bytes in the command if it is the largest
// we have seen so far.
if(InBuffer.BufferSize > CommandResponseSizes.largestCommandSize)
459 {
460 CommandResponseSizes.largestCommandSize = InBuffer.BufferSize;
461 memcpy(&CommandResponseSizes.largestCommand,
462 &InputBuffer[6], sizeof(UINT32));
463 }
464
465 _rpc Send_Command(locality, InBuffer, &OutBuffer);
466 // record the number of bytes in the response if it is the largest
467 // we have seen so far.
468 if(OutBuffer.BufferSize > CommandResponseSizes.largestResponseSize)
469 {
470 CommandResponseSizes.largestResponseSize
471 = OutBuffer.BufferSize;
472 memcpy(&CommandResponseSizes.largestResponse,
473 &OutputBuffer[6], sizeof(UINT32));
474 }
ok = WriteVarBytes(s,
(char*) OutBuffer.Buffer,
OutBuffer.BufferSize);
if(!ok)
return TRUE;
break;
481
482 case TPM_REMOTE_HANDSHAKE:
483 ok = ReadBytes(s, (char*)&clientVersion, 4);
484 if(!ok)
485 return TRUE;
486 if( clientVersion == 0 )
487 {
488 printf("Unsupported client version (0).\n");
489 return TRUE;
490 }
491 ok &= WriteUINT32(s, ServerVersion);
492 ok &= WriteUINT32(s,
493 tpmInRawMode | tpmPlatformAvailable | tpmSupportsPP);
494 break;
495
496 case TPM_SET_ALTERNATIVE_RESULT:
497 | ok = ReadBytes(s, (char*)&result, 4); | |
498 | if(!ok) | |
499 | return TRUE; | |
500 | // Alternative result is not applicable to the simulator. | |
501 | break; | |
502 | ||
503 | case TPM_SESSION_END: | |
504 | // Client signaled end-of-session | |
505 | return TRUE; | |
506 | ||
507 | case TPM_STOP: | |
508 | // Client requested the simulator to exit | |
509 | return FALSE; | |
510 | default: | |
511 | printf("Unrecognized TPM interface command %d\n", Command); | |
512 | return TRUE; | |
513 | } | |
514 | ok = WriteUINT32(s,0); | |
515 | if(!ok) | |
516 | return TRUE; | |
517 | } | |
518 | return FALSE; | |
519 | } |
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.
Includes and Data Definitions
#define _SWAP_H // Preclude inclusion of unnecessary simulator header
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <setjmp.h>
#include "bool.h"
#include "Platform.h"
#include "ExecCommand_fp.h"
#include "Manufacture_fp.h"
#include "DRTM_fp.h"
#include "_TPM_Init_fp.h"
#include "TpmFail_fp.h"
#include <windows.h>
#include "TpmTcpProtocol.h"
static BOOL s_isPowerOn = FALSE;
This function processes a power-on indicataion. Amoung other things, it calls the _TPM_Init() hangler.
void
_rpc Signal_PowerOn(
BOOL isReset
19 )
20 {
// if power is on and this is not a call to do TPM reset then return
if(s_isPowerOn && !isReset)
return;
24
// If this is a reset but power is not on, then return
if(isReset && !s_isPowerOn)
return;
28
// Pass power on signal to platform
if(isReset)
_plat Signal_Reset();
else
_plat Signal_PowerOn(); 34
// Pass power on signal to TPM
_TPM_Init(); 37
// Set state as power on
s_isPowerOn = TRUE; 40 }
This function processes the power off indication. Its primary funtion is to set a flag indicating that the next power on indication should cause _TPM_Init() to be called.
void
_rpc Signal_PowerOff(
void
44 )
45 {
46 if(!s_isPowerOn) return; 47
// Pass power off signal to platform
_plat Signal_PowerOff(); 50
51 s_isPowerOn = FALSE; 52
53 return; 54 }
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.
void
_rpc ForceFailureMode(
void
58 )
59 {
60 SetForceFailureMode(); 61 }
_rpc__Signal_PhysicalPresenceOn()
This function is called to simulate activation of the physical presence pin.
void
_rpc Signal_PhysicalPresenceOn(
void
65 )
66 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 69
// Pass physical presence on to platform
_plat Signal_PhysicalPresenceOn(); 72
73 return; 74 }
_rpc__Signal_PhysicalPresenceOff()
This function is called to simulate deactivation of the physical presence pin.
void
_rpc Signal_PhysicalPresenceOff(
void
78 )
79 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 82
// Pass physical presence off to platform
_plat Signal_PhysicalPresenceOff(); 85
86 return; 87 }
This function is called to simulate a _TPM_Hash_Start() event. It will call
void
_rpc Signal_Hash_Start(
void
91 )
92 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 95
// Pass _TPM_Hash_Start signal to TPM
Signal_Hash_Start();
return; 99 }
This function is called to simulate a _TPM_Hash_Data() event.
void
_rpc Signal_Hash_Data(
_IN_BUFFER input
103 )
104 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 107
// Pass _TPM_Hash_Data signal to TPM
Signal_Hash_Data(input.BufferSize, input.Buffer);
return;
111 }
This function is called to simulate a _TPM_Hash_End() event.
void
_rpc Signal_HashEnd(
void
115 )
116 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 119
// Pass _TPM_HashEnd signal to TPM
Signal_Hash_End();
return;
123 }
Command interface Entry of a RPC call
void
_rpc Send_Command(
unsigned char locality,
_IN_BUFFER request,
_OUT_BUFFER *response
129 )
130 {
// If TPM is power off, reject any commands.
if(!s_isPowerOn) {
response->BufferSize = 0;
return;
135 }
// Set the locality of the command so that it doesn't change during the command
_plat LocalitySet(locality);
// Do implementation-specific command dispatch
ExecuteCommand(request.BufferSize, request.Buffer,
&response->BufferSize, &response->Buffer);
return; 142
143 }
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 perodically check this indication to see if it should abort the current command processing and returned TPM_RC_CANCELLED.
void
_rpc Signal_CancelOn(
void
147 )
148 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 151
// Set the platform canceling flag.
_plat SetCancel(); 154
155 return;
156 }
This function is used to turn off the indication to cancel a command in process.
void
_rpc Signal_CancelOff(
void
160 )
161 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 164
// Set the platform canceling flag.
_plat ClearCancel(); 167
168 return;
169 }
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.
void
_rpc Signal_NvOn(
void
173 )
174 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 177
_plat SetNvAvail();
return;
180 }
This function is used to set the indication that NV memory is no longer available.
void
_rpc Signal_NvOff(
void
184 )
185 {
// If TPM is power off, reject this signal
if(!s_isPowerOn) return; 188
_plat ClearNvAvail();
return;
191 }
This function is used to stop the TPM simulator.
void
_rpc Shutdown(
void
195 )
196 {
197 RPC_STATUS status; 198
// Stop TPM
TPM_TearDown(); 201
status = RpcMgmtStopServerListening(NULL);
if (status != RPC_S_OK)
204 {
printf_s("RpcMgmtStopServerListening returned: 0x%x\n", status);
exit(status);
207 }
208
status = RpcServerUnregisterIf(NULL, NULL, FALSE);
if (status != RPC_S_OK)
211 {
printf_s("RpcServerUnregisterIf returned 0x%x\n", status);
exit(status);
214 }
215 }
This file contains the entry point for the simulator.
Includes, Defines, Data Definitions, and Function Prototypes
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <windows.h>
#include <strsafe.h>
#include "string.h"
#include "TpmTcpProtocol.h"
#include "..\tpm\include\TpmBuildSwitches.h"
#include "..\tpm\include\prototypes\Manufacture_fp.h"
#define PURPOSE \
"TPM Reference Simulator.\nCopyright Microsoft 2010, 2011.\n"
#define DEFAULT_TPM_PORT 2321
void* MainPointer;
int _plat NVEnable(void* platParameters);
void _plat NVDisable();
int StartTcpServer(int PortNumber);
This function prints the proper calling sequence for the simulator.
void
Usage(
char *pszProgramName 21 )
22 {
fprintf_s(stderr, "%s", PURPOSE);
fprintf_s(stderr, "Usage:\n");
fprintf_s(stderr, "%s - Starts the TPM server listening on port %d\n",
pszProgramName, DEFAULT_TPM_PORT);
fprintf_s(stderr,
"%s PortNum - Starts the TPM server listening on port PortNum\n",
pszProgramName);
fprintf_s(stderr, "%s ? - This message\n", pszProgramName);
exit(1); 32 }
This is the main entry point for the simulator.
main: register the interface, start listening for clients
void cdecl
main(
int argc,
char *argv[]
37 )
38 | { | |
39 | int portNum = DEFAULT_TPM_PORT; | |
40 | if(argc>2) | |
41 | { | |
42 | Usage(argv[0]); | |
43 | } | |
44 | ||
45 | if(argc==2) | |
46 | { | |
47 | if(strcmp(argv[1], "?") ==0) | |
48 | { | |
49 | Usage(argv[0]); | |
50 | } | |
51 | portNum = atoi(argv[1]); | |
52 | if(portNum <=0 || portNum>65535) | |
53 | { | |
54 | Usage(argv[0]); | |
55 | } | |
56 | } | |
57 | _plat NVEnable(NULL); | |
58 | if(TPM_Manufacture(1) != 0) | |
59 | { | |
60 | exit(1); | |
61 | } | |
62 | // Coverage test - repeated manufacturing attempt | |
63 | if(TPM_Manufacture(0) != 1) | |
64 | { | |
65 | exit(2); | |
66 | } | |
67 | // Coverage test - re-manufacturing | |
68 | TPM_TearDown(); | |
69 | if(TPM_Manufacture(1) != 0) | |
70 | { | |
71 | exit(3); | |
72 | } | |
73 | // Disable NV memory | |
74 | _plat NVDisable(); | |
75 | ||
76 | StartTcpServer(portNum); | |
77 | return; | |
78 | } |