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