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