1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "Attest_spt_fp.h"
//
//
// Functions
//
// FillInAttestInfo()
//
// 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
)
{
TPM_RC result;
TPMI_RH_HIERARCHY signHierarhcy;
result = CryptSelectSignScheme(signHandle, scheme);
if(result != TPM_RC_SUCCESS)
return result;
// Magic number
attest->magic = TPM_GENERATED_VALUE;
if(signHandle == TPM_RH_NULL)
{
BYTE *buffer;
INT32 bufferSize;
// For null sign handle, the QN is TPM_RH_NULL
buffer = attest->qualifiedSigner.t.name;
bufferSize = sizeof(TPM_HANDLE);
attest->qualifiedSigner.t.size =
TPM_HANDLE_Marshal(&signHandle, &buffer, &bufferSize);
}
else
{
// Certifying object qualified name
// if the scheme is anonymous, this is an empty buffer
if(CryptIsSchemeAnonymous(scheme->scheme))
attest->qualifiedSigner.t.size = 0;
else
ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner);
}
// current clock in plain text
TimeFillInfo(&attest->clockInfo);
// Firmware version in plain text
attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8));
attest->firmwareVersion += gp.firmwareV2;
// Get the hierarchy of sign object. For NULL sign handle, the hierarchy
// will be TPM_RH_NULL
signHierarhcy = EntityGetHierarchy(signHandle);
if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT)
{
// For sign object is not in platform or endorsement hierarchy,
// obfuscate the clock and firmwereVersion information
UINT64 obfuscation[2];
TPMI_ALG_HASH hashAlg;
// Get hash algorithm
if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER)
{
hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
}
else
{
OBJECT *signObject = NULL;
signObject = ObjectGet(signHandle);
hashAlg = signObject->publicArea.nameAlg;
}
KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE",
&attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL);
// Obfuscate data
attest->firmwareVersion += obfuscation[0];
attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32);
attest->clockInfo.restartCount += (UINT32)obfuscation[1];
}
// External data
if(CryptIsSchemeAnonymous(scheme->scheme))
attest->extraData.t.size = 0;
else
{
// If we move the data to the attestation structure, then we will not use
// it in the signing operation except as part of the signed data
attest->extraData = *data;
data->t.size = 0;
}
return TPM_RC_SUCCESS;
}
//
//
// SignAttestInfo()
//
// 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
)
{
TPM_RC result;
TPMI_ALG_HASH hashAlg;
BYTE *buffer;
INT32 bufferSize;
HASH_STATE hashState;
TPM2B_DIGEST digest;
// Marshal TPMS_ATTEST structure for hash
buffer = attest->t.attestationData;
bufferSize = sizeof(TPMS_ATTEST);
attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, &bufferSize);
if(signHandle == TPM_RH_NULL)
{
signature->sigAlg = TPM_ALG_NULL;
}
else
{
// 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)
{
// 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;
}
// 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);
// If there is qualifying data, need to rehash the the data
// hash(qualifyingData || hash(attestationData))
if(qualifyingData->t.size != 0)
{
CryptStartHash(hashAlg, &hashState);
CryptUpdateDigest(&hashState,
qualifyingData->t.size,
qualifyingData->t.buffer);
CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer);
CryptCompleteHash2B(&hashState, &digest.b);
}
// Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or
// TPM_RC_ATTRIBUTES error may be returned at this point
return CryptSign(signHandle,
scheme,
&digest,
signature);
}
return TPM_RC_SUCCESS;
}
|