/src/libtpms/src/tpm2/AttestationCommands.c
Line | Count | Source |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* Attestation Commands */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* $Id: AttestationCommands.c 1658 2021-01-22 23:14:01Z kgoldman $ */ |
7 | | /* */ |
8 | | /* Licenses and Notices */ |
9 | | /* */ |
10 | | /* 1. Copyright Licenses: */ |
11 | | /* */ |
12 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
13 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
14 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
15 | | /* derivative works, distribute, display and perform the Source Code and */ |
16 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
17 | | /* */ |
18 | | /* - The TCG grants to the user of the other parts of the specification */ |
19 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
20 | | /* display, and perform the specification solely for the purpose of */ |
21 | | /* developing products based on such documents. */ |
22 | | /* */ |
23 | | /* 2. Source Code Distribution Conditions: */ |
24 | | /* */ |
25 | | /* - Redistributions of Source CoDe must retain the above copyright licenses, */ |
26 | | /* this list of conditions and the following disclaimers. */ |
27 | | /* */ |
28 | | /* - Redistributions in binary form must reproduce the above copyright */ |
29 | | /* licenses, this list of conditions and the following disclaimers in the */ |
30 | | /* documentation and/or other materials provided with the distribution. */ |
31 | | /* */ |
32 | | /* 3. Disclaimers: */ |
33 | | /* */ |
34 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
35 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
36 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
37 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
38 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
39 | | /* information on specification licensing rights available through TCG */ |
40 | | /* membership agreements. */ |
41 | | /* */ |
42 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
43 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
44 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
45 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
46 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
47 | | /* */ |
48 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
49 | | /* liability, including liability for infringement of any proprietary */ |
50 | | /* rights, relating to use of information in this specification and to the */ |
51 | | /* implementation of this specification, and TCG disclaims all liability for */ |
52 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
53 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
54 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
55 | | /* arising in any way out of use or reliance upon this specification or any */ |
56 | | /* information herein. */ |
57 | | /* */ |
58 | | /* (c) Copyright IBM Corp. and others, 2016 - 2021 */ |
59 | | /* */ |
60 | | /********************************************************************************/ |
61 | | |
62 | | #include "Tpm.h" |
63 | | #include "Attest_spt_fp.h" |
64 | | #include "Certify_fp.h" |
65 | | #if CC_Certify // Conditional expansion of this file |
66 | | TPM_RC |
67 | | TPM2_Certify( |
68 | | Certify_In *in, // IN: input parameter list |
69 | | Certify_Out *out // OUT: output parameter list |
70 | | ) |
71 | 0 | { |
72 | 0 | TPMS_ATTEST certifyInfo; |
73 | 0 | OBJECT *signObject = HandleToObject(in->signHandle); |
74 | 0 | OBJECT *certifiedObject = HandleToObject(in->objectHandle); |
75 | | // Input validation |
76 | 0 | if(!IsSigningObject(signObject)) |
77 | 0 | return TPM_RCS_KEY + RC_Certify_signHandle; |
78 | 0 | if(!CryptSelectSignScheme(signObject, &in->inScheme)) |
79 | 0 | return TPM_RCS_SCHEME + RC_Certify_inScheme; |
80 | | // Command Output |
81 | | // Filling in attest information |
82 | | // Common fields |
83 | 0 | FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, |
84 | 0 | &certifyInfo); |
85 | | // Certify specific fields |
86 | 0 | certifyInfo.type = TPM_ST_ATTEST_CERTIFY; |
87 | | // NOTE: the certified object is not allowed to be TPM_ALG_NULL so |
88 | | // 'certifiedObject' will never be NULL |
89 | 0 | pAssert_RC(certifiedObject != NULL); // should have been filtered earlier. |
90 | 0 | certifyInfo.attested.certify.name = certifiedObject->name; |
91 | | |
92 | | // When using an anonymous signing scheme, need to set the qualified Name to the |
93 | | // empty buffer to avoid correlation between keys |
94 | 0 | if(CryptIsSchemeAnonymous(in->inScheme.scheme)) |
95 | 0 | certifyInfo.attested.certify.qualifiedName.t.size = 0; |
96 | 0 | else |
97 | 0 | certifyInfo.attested.certify.qualifiedName = certifiedObject->qualifiedName; |
98 | | |
99 | | // Sign attestation structure. A NULL signature will be returned if |
100 | | // signHandle is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE, |
101 | | // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned |
102 | | // by SignAttestInfo() |
103 | 0 | return SignAttestInfo(signObject, &in->inScheme, &certifyInfo, |
104 | 0 | &in->qualifyingData, &out->certifyInfo, &out->signature); |
105 | 0 | } |
106 | | #endif // CC_Certify |
107 | | #include "Tpm.h" |
108 | | #include "Attest_spt_fp.h" |
109 | | #include "CertifyCreation_fp.h" |
110 | | #if CC_CertifyCreation // Conditional expansion of this file |
111 | | TPM_RC |
112 | | TPM2_CertifyCreation( |
113 | | CertifyCreation_In *in, // IN: input parameter list |
114 | | CertifyCreation_Out *out // OUT: output parameter list |
115 | | ) |
116 | 0 | { |
117 | 0 | TPMT_TK_CREATION ticket; |
118 | 0 | TPMS_ATTEST certifyInfo; |
119 | 0 | OBJECT *certified = HandleToObject(in->objectHandle); |
120 | 0 | OBJECT *signObject = HandleToObject(in->signHandle); |
121 | | // Input Validation |
122 | 0 | if(!IsSigningObject(signObject)) |
123 | 0 | return TPM_RCS_KEY + RC_CertifyCreation_signHandle; |
124 | 0 | if(!CryptSelectSignScheme(signObject, &in->inScheme)) |
125 | 0 | return TPM_RCS_SCHEME + RC_CertifyCreation_inScheme; |
126 | | |
127 | 0 | pAssert_RC(certified != NULL); |
128 | | // CertifyCreation specific input validation |
129 | | // Re-compute ticket |
130 | 0 | TicketComputeCreation(in->creationTicket.hierarchy, &certified->name, |
131 | 0 | &in->creationHash, &ticket); |
132 | | // Compare ticket |
133 | 0 | if(!MemoryEqual2B(&ticket.digest.b, &in->creationTicket.digest.b)) |
134 | 0 | return TPM_RCS_TICKET + RC_CertifyCreation_creationTicket; |
135 | | // Command Output |
136 | | // Common fields |
137 | 0 | FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, |
138 | 0 | &certifyInfo); |
139 | | // CertifyCreation specific fields |
140 | | // Attestation type |
141 | 0 | certifyInfo.type = TPM_ST_ATTEST_CREATION; |
142 | 0 | certifyInfo.attested.creation.objectName = certified->name; |
143 | | // Copy the creationHash |
144 | 0 | certifyInfo.attested.creation.creationHash = in->creationHash; |
145 | | // Sign attestation structure. A NULL signature will be returned if |
146 | | // signObject is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE, |
147 | | // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned at |
148 | | // this point |
149 | 0 | return SignAttestInfo(signObject, &in->inScheme, &certifyInfo, |
150 | 0 | &in->qualifyingData, &out->certifyInfo, |
151 | 0 | &out->signature); |
152 | 0 | } |
153 | | #endif // CC_CertifyCreation |
154 | | #include "Tpm.h" |
155 | | #include "Attest_spt_fp.h" |
156 | | #include "GetSessionAuditDigest_fp.h" |
157 | | #if CC_GetSessionAuditDigest // Conditional expansion of this file |
158 | | TPM_RC |
159 | | TPM2_GetSessionAuditDigest( |
160 | | GetSessionAuditDigest_In *in, // IN: input parameter list |
161 | | GetSessionAuditDigest_Out *out // OUT: output parameter list |
162 | | ) |
163 | 0 | { |
164 | 0 | SESSION* session = SessionGet(in->sessionHandle); |
165 | 0 | pAssert_RC(session); |
166 | 0 | TPMS_ATTEST auditInfo; |
167 | 0 | OBJECT* signObject = HandleToObject(in->signHandle); |
168 | | // Input Validation |
169 | 0 | if(!IsSigningObject(signObject)) |
170 | 0 | return TPM_RCS_KEY + RC_GetSessionAuditDigest_signHandle; |
171 | 0 | if(!CryptSelectSignScheme(signObject, &in->inScheme)) |
172 | 0 | return TPM_RCS_SCHEME + RC_GetSessionAuditDigest_inScheme; |
173 | | // session must be an audit session |
174 | 0 | if(session->attributes.isAudit == CLEAR) |
175 | 0 | return TPM_RCS_TYPE + RC_GetSessionAuditDigest_sessionHandle; |
176 | | // Command Output |
177 | | // Fill in attest information common fields |
178 | 0 | FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, |
179 | 0 | &auditInfo); |
180 | | // SessionAuditDigest specific fields |
181 | 0 | auditInfo.type = TPM_ST_ATTEST_SESSION_AUDIT; |
182 | 0 | auditInfo.attested.sessionAudit.sessionDigest = session->u2.auditDigest; |
183 | | // Exclusive audit session |
184 | 0 | auditInfo.attested.sessionAudit.exclusiveSession |
185 | 0 | = (g_exclusiveAuditSession == in->sessionHandle); |
186 | | // Sign attestation structure. A NULL signature will be returned if |
187 | | // signObject is NULL. |
188 | 0 | return SignAttestInfo(signObject, &in->inScheme, &auditInfo, |
189 | 0 | &in->qualifyingData, &out->auditInfo, |
190 | 0 | &out->signature); |
191 | 0 | } |
192 | | #endif // CC_GetSessionAuditDigest |
193 | | #include "Tpm.h" |
194 | | #include "Attest_spt_fp.h" |
195 | | #include "GetCommandAuditDigest_fp.h" |
196 | | #if CC_GetCommandAuditDigest // Conditional expansion of this file |
197 | | TPM_RC |
198 | | TPM2_GetCommandAuditDigest( |
199 | | GetCommandAuditDigest_In *in, // IN: input parameter list |
200 | | GetCommandAuditDigest_Out *out // OUT: output parameter list |
201 | | ) |
202 | 0 | { |
203 | 0 | TPM_RC result; |
204 | 0 | TPMS_ATTEST auditInfo; |
205 | 0 | OBJECT *signObject = HandleToObject(in->signHandle); |
206 | | // Input validation |
207 | 0 | if(!IsSigningObject(signObject)) |
208 | 0 | return TPM_RCS_KEY + RC_GetCommandAuditDigest_signHandle; |
209 | 0 | if(!CryptSelectSignScheme(signObject, &in->inScheme)) |
210 | 0 | return TPM_RCS_SCHEME + RC_GetCommandAuditDigest_inScheme; |
211 | | // Command Output |
212 | | // Fill in attest information common fields |
213 | 0 | FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, |
214 | 0 | &auditInfo); |
215 | | // CommandAuditDigest specific fields |
216 | 0 | auditInfo.type = TPM_ST_ATTEST_COMMAND_AUDIT; |
217 | 0 | auditInfo.attested.commandAudit.digestAlg = gp.auditHashAlg; |
218 | 0 | auditInfo.attested.commandAudit.auditCounter = gp.auditCounter; |
219 | | // Copy command audit log |
220 | 0 | auditInfo.attested.commandAudit.auditDigest = gr.commandAuditDigest; |
221 | 0 | CommandAuditGetDigest(&auditInfo.attested.commandAudit.commandDigest); |
222 | | // Sign attestation structure. A NULL signature will be returned if |
223 | | // signHandle is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE, |
224 | | // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned at |
225 | | // this point |
226 | 0 | result = SignAttestInfo(signObject, &in->inScheme, &auditInfo, |
227 | 0 | &in->qualifyingData, &out->auditInfo, |
228 | 0 | &out->signature); |
229 | | // Internal Data Update |
230 | 0 | if(result == TPM_RC_SUCCESS && in->signHandle != TPM_RH_NULL) |
231 | | // Reset log |
232 | 0 | gr.commandAuditDigest.t.size = 0; |
233 | 0 | return result; |
234 | 0 | } |
235 | | #endif // CC_GetCommandAuditDigest |
236 | | #include "Tpm.h" |
237 | | #include "Attest_spt_fp.h" |
238 | | #include "GetTime_fp.h" |
239 | | #if CC_GetTime // Conditional expansion of this file |
240 | | TPM_RC |
241 | | TPM2_GetTime( |
242 | | GetTime_In *in, // IN: input parameter list |
243 | | GetTime_Out *out // OUT: output parameter list |
244 | | ) |
245 | 0 | { |
246 | 0 | TPMS_ATTEST timeInfo; |
247 | 0 | OBJECT *signObject = HandleToObject(in->signHandle); |
248 | | // Input Validation |
249 | 0 | if(!IsSigningObject(signObject)) |
250 | 0 | return TPM_RCS_KEY + RC_GetTime_signHandle; |
251 | 0 | if(!CryptSelectSignScheme(signObject, &in->inScheme)) |
252 | 0 | return TPM_RCS_SCHEME + RC_GetTime_inScheme; |
253 | | // Command Output |
254 | | // Fill in attest common fields |
255 | 0 | FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, &timeInfo); |
256 | | // GetClock specific fields |
257 | 0 | timeInfo.type = TPM_ST_ATTEST_TIME; |
258 | 0 | timeInfo.attested.time.time.time = g_time; |
259 | 0 | TimeFillInfo(&timeInfo.attested.time.time.clockInfo); |
260 | | // Firmware version in plain text |
261 | 0 | timeInfo.attested.time.firmwareVersion |
262 | 0 | = (((UINT64)gp.firmwareV1) << 32) + gp.firmwareV2; |
263 | | // Sign attestation structure. A NULL signature will be returned if |
264 | | // signObject is NULL. |
265 | 0 | return SignAttestInfo(signObject, &in->inScheme, &timeInfo, &in->qualifyingData, |
266 | 0 | &out->timeInfo, &out->signature); |
267 | 0 | } |
268 | | #endif // CC_GetTime |
269 | | #include "Tpm.h" |
270 | | #include "CertifyX509_fp.h" |
271 | | #include "X509.h" |
272 | | #include "TpmASN1_fp.h" |
273 | | #include "X509_spt_fp.h" |
274 | | #include "Attest_spt_fp.h" |
275 | | #if CC_CertifyX509 // Conditional expansion of this file |
276 | | #if CERTIFYX509_DEBUG |
277 | | # include "tpm_to_platform_interface.h" |
278 | | #endif |
279 | | |
280 | | /* Error Returns Meaning*/ |
281 | | /* TPM_RC_ATTRIBUTES the attributes of objectHandle are not compatible with the KeyUsage() or TPMA_OBJECT values in the extensions fields */ |
282 | | /* TPM_RC_BINDING the public and private portions of the key are not properly bound. */ |
283 | | /* TPM_RC_HASH the hash algorithm in the scheme is not supported */ |
284 | | /* TPM_RC_KEY signHandle does not reference a signing key; */ |
285 | | /* TPM_RC_SCHEME the scheme is not compatible with sign key type, or input scheme is not compatible with default scheme, or the chosen scheme is not a valid sign scheme */ |
286 | | /* TPM_RC_VALUE most likely a problem with the format of partialCertificate */ |
287 | | TPM_RC |
288 | | TPM2_CertifyX509( |
289 | | CertifyX509_In *in, // IN: input parameter list |
290 | | CertifyX509_Out *out // OUT: output parameter list |
291 | | ) |
292 | 0 | { |
293 | 0 | TPM_RC result; |
294 | 0 | OBJECT *signKey = HandleToObject(in->signHandle); |
295 | 0 | OBJECT *object = HandleToObject(in->objectHandle); |
296 | 0 | HASH_STATE hash; |
297 | 0 | INT16 length; // length for a tagged element |
298 | 0 | ASN1UnmarshalContext ctx; |
299 | 0 | ASN1MarshalContext ctxOut; |
300 | 0 | pAssert_RC(object != NULL); |
301 | | |
302 | | // certTBS holds an array of pointers and lengths. Each entry references the |
303 | | // corresponding value in a TBSCertificate structure. For example, the 1th |
304 | | // element references the version number |
305 | 0 | stringRef certTBS[REF_COUNT] = {{0}}; |
306 | 0 | #define ALLOWED_SEQUENCES (SUBJECT_PUBLIC_KEY_REF - SIGNATURE_REF) |
307 | 0 | stringRef partial[ALLOWED_SEQUENCES] = {{0}}; |
308 | 0 | INT16 countOfSequences = 0; |
309 | 0 | INT16 i; |
310 | | // |
311 | | #if CERTIFYX509_DEBUG |
312 | | DebugFileInit(); |
313 | | DebugDumpBuffer(in->partialCertificate.t.size, in->partialCertificate.t.buffer, |
314 | | "partialCertificate"); |
315 | | #endif |
316 | | |
317 | | // Input Validation |
318 | 0 | if(in->reserved.b.size != 0) |
319 | 0 | return TPM_RC_SIZE + RC_CertifyX509_reserved; |
320 | | // signing key must be able to sign |
321 | 0 | if(!IsSigningObject(signKey)) |
322 | 0 | return TPM_RCS_KEY + RC_CertifyX509_signHandle; |
323 | | // Pick a scheme for sign. If the input sign scheme is not compatible with |
324 | | // the default scheme, return an error. |
325 | 0 | if(!CryptSelectSignScheme(signKey, &in->inScheme)) |
326 | 0 | return TPM_RCS_SCHEME + RC_CertifyX509_inScheme; |
327 | | // Make sure that the public Key encoding is known |
328 | 0 | if(X509AddPublicKey(NULL, object) == 0) |
329 | 0 | return TPM_RCS_ASYMMETRIC + RC_CertifyX509_objectHandle; |
330 | | // Unbundle 'partialCertificate'. |
331 | | // Initialize the unmarshaling context |
332 | 0 | if(!ASN1UnmarshalContextInitialize(&ctx, in->partialCertificate.t.size, |
333 | 0 | in->partialCertificate.t.buffer)) |
334 | 0 | return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate; |
335 | | // Make sure that this is a constructed SEQUENCE |
336 | 0 | length = ASN1NextTag(&ctx); |
337 | | // Must be a constructed SEQUENCE that uses all of the input parameter |
338 | 0 | if((ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE)) |
339 | 0 | || ((ctx.offset + length) != in->partialCertificate.t.size)) |
340 | 0 | return TPM_RCS_SIZE + RC_CertifyX509_partialCertificate; |
341 | | |
342 | | // This scans through the contents of the outermost SEQUENCE. This would be the |
343 | | // 'issuer', 'validity', 'subject', 'issuerUniqueID' (optional), |
344 | | // 'subjectUniqueID' (optional), and 'extensions.' |
345 | 0 | while(ctx.offset < ctx.size) |
346 | 0 | { |
347 | 0 | INT16 startOfElement = ctx.offset; |
348 | | // |
349 | | // Read the next tag and length field. |
350 | 0 | length = ASN1NextTag(&ctx); |
351 | 0 | if(length < 0) |
352 | 0 | break; |
353 | 0 | if(ctx.tag == ASN1_CONSTRUCTED_SEQUENCE) |
354 | 0 | { |
355 | 0 | partial[countOfSequences].buf = &ctx.buffer[startOfElement]; |
356 | 0 | ctx.offset += length; |
357 | 0 | partial[countOfSequences].len = (INT16)ctx.offset - startOfElement; |
358 | 0 | if(++countOfSequences > ALLOWED_SEQUENCES) |
359 | 0 | break; |
360 | 0 | } |
361 | 0 | else if(ctx.tag == X509_EXTENSIONS) |
362 | 0 | { |
363 | 0 | if(certTBS[EXTENSIONS_REF].len != 0) |
364 | 0 | return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate; |
365 | 0 | certTBS[EXTENSIONS_REF].buf = &ctx.buffer[startOfElement]; |
366 | 0 | ctx.offset += length; |
367 | 0 | certTBS[EXTENSIONS_REF].len = |
368 | 0 | (INT16)ctx.offset - startOfElement; |
369 | 0 | } |
370 | 0 | else |
371 | 0 | return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate; |
372 | 0 | } |
373 | | // Make sure that we used all of the data and found at least the required |
374 | | // number of elements. |
375 | 0 | if((ctx.offset != ctx.size) || (countOfSequences < 3) |
376 | 0 | || (countOfSequences > 4) |
377 | 0 | || (certTBS[EXTENSIONS_REF].buf == NULL)) |
378 | 0 | return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate; |
379 | | // Now that we know how many sequences there were, we can put them where they |
380 | | // belong |
381 | 0 | for(i = 0; i < countOfSequences; i++) |
382 | 0 | certTBS[SUBJECT_KEY_REF - i] = partial[countOfSequences - 1 - i]; |
383 | | |
384 | | // If only three SEQUENCES, then the TPM needs to produce the signature algorithm. |
385 | | // See if it can |
386 | 0 | if((countOfSequences == 3) && |
387 | 0 | (X509AddSigningAlgorithm(NULL, signKey, &in->inScheme) == 0)) |
388 | 0 | return TPM_RCS_SCHEME + RC_CertifyX509_signHandle; |
389 | | |
390 | | // Process the extensions |
391 | 0 | result = X509ProcessExtensions(object, &certTBS[EXTENSIONS_REF]); |
392 | 0 | if(result != TPM_RC_SUCCESS) |
393 | | // If the extension has the TPMA_OBJECT extension and the attributes don't |
394 | | // match, then the error code will be TPM_RCS_ATTRIBUTES. Otherwise, the error |
395 | | // indicates a malformed partialCertificate. |
396 | 0 | return result + ((result == TPM_RCS_ATTRIBUTES) |
397 | 0 | ? RC_CertifyX509_objectHandle |
398 | 0 | : RC_CertifyX509_partialCertificate); |
399 | | // Command Output |
400 | | // Create the addedToCertificate values |
401 | | |
402 | | // Build the addedToCertificate from the bottom up. |
403 | | // Initialize the context structure |
404 | 0 | ASN1InitialializeMarshalContext(&ctxOut, sizeof(out->addedToCertificate.t.buffer), |
405 | 0 | out->addedToCertificate.t.buffer); |
406 | | // Place a marker for the overall context |
407 | 0 | ASN1StartMarshalContext(&ctxOut); // SEQUENCE for addedToCertificate |
408 | | |
409 | | // Add the subject public key descriptor |
410 | 0 | certTBS[SUBJECT_PUBLIC_KEY_REF].len = X509AddPublicKey(&ctxOut, object); |
411 | 0 | certTBS[SUBJECT_PUBLIC_KEY_REF].buf = ctxOut.buffer + ctxOut.offset; |
412 | | // If the caller didn't provide the algorithm identifier, create it |
413 | 0 | if(certTBS[SIGNATURE_REF].len == 0) |
414 | 0 | { |
415 | 0 | certTBS[SIGNATURE_REF].len = X509AddSigningAlgorithm(&ctxOut, signKey, |
416 | 0 | &in->inScheme); |
417 | 0 | certTBS[SIGNATURE_REF].buf = ctxOut.buffer + ctxOut.offset; |
418 | 0 | } |
419 | | // Create the serial number value. Use the out->tbsDigest as scratch. |
420 | 0 | { |
421 | 0 | TPM2B *digest = &out->tbsDigest.b; |
422 | | // |
423 | 0 | digest->size = (INT16)CryptHashStart(&hash, signKey->publicArea.nameAlg); |
424 | 0 | pAssert(digest->size != 0); |
425 | | |
426 | | // The serial number size is the smaller of the digest and the vendor-defined |
427 | | // value |
428 | 0 | digest->size = MIN(digest->size, SIZE_OF_X509_SERIAL_NUMBER); |
429 | | // Add all the parts of the certificate other than the serial number |
430 | | // and version number |
431 | 0 | for(i = SIGNATURE_REF; i < REF_COUNT; i++) |
432 | 0 | CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf); |
433 | | // throw in the Name of the signing key... |
434 | 0 | CryptDigestUpdate2B(&hash, &signKey->name.b); |
435 | | // ...and the Name of the signed key. |
436 | 0 | CryptDigestUpdate2B(&hash, &object->name.b); |
437 | | // Done |
438 | 0 | CryptHashEnd2B(&hash, digest); |
439 | 0 | } |
440 | | |
441 | | // Add the serial number |
442 | 0 | certTBS[SERIAL_NUMBER_REF].len = |
443 | 0 | ASN1PushInteger(&ctxOut, out->tbsDigest.t.size, out->tbsDigest.t.buffer); |
444 | 0 | certTBS[SERIAL_NUMBER_REF].buf = ctxOut.buffer + ctxOut.offset; |
445 | | |
446 | | // Add the static version number |
447 | 0 | ASN1StartMarshalContext(&ctxOut); |
448 | 0 | ASN1PushUINT(&ctxOut, 2); |
449 | 0 | certTBS[VERSION_REF].len = |
450 | 0 | ASN1EndEncapsulation(&ctxOut, ASN1_APPLICAIION_SPECIFIC); |
451 | 0 | certTBS[VERSION_REF].buf = ctxOut.buffer + ctxOut.offset; |
452 | | |
453 | | // Create a fake tag and length for the TBS in the space used for |
454 | | // 'addedToCertificate' |
455 | 0 | { |
456 | 0 | for(length = 0, i = 0; i < REF_COUNT; i++) |
457 | 0 | length += certTBS[i].len; |
458 | | // Put a fake tag and length into the buffer for use in the tbsDigest |
459 | 0 | certTBS[ENCODED_SIZE_REF].len = |
460 | 0 | ASN1PushTagAndLength(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE, length); |
461 | 0 | certTBS[ENCODED_SIZE_REF].buf = ctxOut.buffer + ctxOut.offset; |
462 | | // Restore the buffer pointer to add back the number of octets used for the |
463 | | // tag and length |
464 | 0 | ctxOut.offset += certTBS[ENCODED_SIZE_REF].len; |
465 | 0 | } |
466 | | // sanity check |
467 | 0 | if(ctxOut.offset < 0) |
468 | 0 | return TPM_RC_FAILURE; |
469 | | // Create the tbsDigest to sign |
470 | 0 | out->tbsDigest.t.size = CryptHashStart(&hash, in->inScheme.details.any.hashAlg); |
471 | 0 | for(i = 0; i < REF_COUNT; i++) |
472 | 0 | CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf); |
473 | 0 | CryptHashEnd2B(&hash, &out->tbsDigest.b); |
474 | |
|
475 | | #if CERTIFYX509_DEBUG |
476 | | { |
477 | | BYTE fullTBS[4096]; |
478 | | BYTE *fill = fullTBS; |
479 | | int j; |
480 | | for (j = 0; j < REF_COUNT; j++) |
481 | | { |
482 | | MemoryCopy(fill, certTBS[j].buf, certTBS[j].len); |
483 | | fill += certTBS[j].len; |
484 | | } |
485 | | DebugDumpBuffer((int)(fill - &fullTBS[0]), fullTBS, "\nfull TBS"); |
486 | | } |
487 | | #endif |
488 | | |
489 | | // Finish up the processing of addedToCertificate |
490 | | // Create the actual tag and length for the addedToCertificate structure |
491 | 0 | out->addedToCertificate.t.size = |
492 | 0 | ASN1EndEncapsulation(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE); |
493 | | // Now move all the addedToContext to the start of the buffer |
494 | 0 | MemoryCopy(out->addedToCertificate.t.buffer, ctxOut.buffer + ctxOut.offset, |
495 | 0 | out->addedToCertificate.t.size); |
496 | | #if CERTIFYX509_DEBUG |
497 | | DebugDumpBuffer(out->addedToCertificate.t.size, out->addedToCertificate.t.buffer, |
498 | | "\naddedToCertificate"); |
499 | | #endif |
500 | | // only thing missing is the signature |
501 | 0 | result = CryptSign(signKey, &in->inScheme, &out->tbsDigest, &out->signature); |
502 | |
|
503 | 0 | return result; |
504 | 0 | } |
505 | | #endif // CC_CertifyX509 |