1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 #include "Tpm.h"
36 #include "CertifyX509_fp.h"
37 #include "X509.h"
38 #include "TpmASN1_fp.h"
39 #include "X509_spt_fp.h"
40 #include "Attest_spt_fp.h"
41 #if CERTIFYX509_DEBUG
42 #include "Platform_fp.h"
43 #endif
44
45 #if CC_CertifyX509 // Conditional expansion of this file
46
47 /*(See part 3 specification)
48 // Certify using an X509-formatted certificate
49 */
50 // return type: TPM_RC
51 // TPM_RC_ATTRIBUTES the attributes of 'objectHandle' are not compatible
52 // with the KeyUsage or TPMA_OBJECT values in the
53 // extensions fields
54 // TPM_RC_BINDING the public and private portions of the key are not
55 // properly bound.
56 // TPM_RC_HASH the hash algorithm in the scheme is not supported
57 // TPM_RC_KEY 'signHandle' does not reference a signing key;
58 // TPM_RC_SCHEME the scheme is not compatible with sign key type,
59 // or input scheme is not compatible with default
60 // scheme, or the chosen scheme is not a valid
61 // sign scheme
62 // TPM_RC_VALUE most likely a problem with the format of
63 // 'partialCertificate'
64 TPM_RC
TPM2_CertifyX509(CertifyX509_In * in,CertifyX509_Out * out)65 TPM2_CertifyX509(
66 CertifyX509_In *in, // IN: input parameter list
67 CertifyX509_Out *out // OUT: output parameter list
68 )
69 {
70 TPM_RC result;
71 OBJECT *signKey = HandleToObject(in->signHandle);
72 OBJECT *object = HandleToObject(in->objectHandle);
73 HASH_STATE hash;
74 INT16 length; // length for a tagged element
75 ASN1UnmarshalContext ctx;
76 ASN1MarshalContext ctxOut;
77 // certTBS holds an array of pointers and lengths. Each entry references the
78 // corresponding value in a TBSCertificate structure. For example, the 1th
79 // element references the version number
80 stringRef certTBS[REF_COUNT] = {0};
81 #define ALLOWED_SEQUENCES (SUBJECT_PUBLIC_KEY_REF - SIGNATURE_REF)
82 stringRef partial[ALLOWED_SEQUENCES] = {0};
83 INT16 countOfSequences = 0;
84 INT16 i;
85 //
86 #if CERTIFYX509_DEBUG
87 DebugFileInit();
88 DebugDumpBuffer(in->partialCertificate.t.size, in->partialCertificate.t.buffer,
89 "partialCertificate");
90 #endif
91
92 // Input Validation
93 if(in->reserved.b.size != 0)
94 return TPM_RC_SIZE + RC_CertifyX509_reserved;
95 // signing key must be able to sign
96 if(!IsSigningObject(signKey))
97 return TPM_RCS_KEY + RC_CertifyX509_signHandle;
98 // Pick a scheme for sign. If the input sign scheme is not compatible with
99 // the default scheme, return an error.
100 if(!CryptSelectSignScheme(signKey, &in->inScheme))
101 return TPM_RCS_SCHEME + RC_CertifyX509_inScheme;
102 // Make sure that the public Key encoding is known
103 if(X509AddPublicKey(NULL, object) == 0)
104 return TPM_RCS_ASYMMETRIC + RC_CertifyX509_objectHandle;
105 // Unbundle 'partialCertificate'.
106 // Initialize the unmarshaling context
107 if(!ASN1UnmarshalContextInitialize(&ctx, in->partialCertificate.t.size,
108 in->partialCertificate.t.buffer))
109 return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
110 // Make sure that this is a constructed SEQUENCE
111 length = ASN1NextTag(&ctx);
112 // Must be a constructed SEQUENCE that uses all of the input parameter
113 if((ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE))
114 || ((ctx.offset + length) != in->partialCertificate.t.size))
115 return TPM_RCS_SIZE + RC_CertifyX509_partialCertificate;
116
117 // This scans through the contents of the outermost SEQUENCE. This would be the
118 // 'issuer', 'validity', 'subject', 'issuerUniqueID' (optional),
119 // 'subjectUniqueID' (optional), and 'extensions.'
120 while(ctx.offset < ctx.size)
121 {
122 INT16 startOfElement = ctx.offset;
123 //
124 // Read the next tag and length field.
125 length = ASN1NextTag(&ctx);
126 if(length < 0)
127 break;
128 if(ctx.tag == ASN1_CONSTRUCTED_SEQUENCE)
129 {
130 partial[countOfSequences].buf = &ctx.buffer[startOfElement];
131 ctx.offset += length;
132 partial[countOfSequences].len = (INT16)ctx.offset - startOfElement;
133 if(++countOfSequences > ALLOWED_SEQUENCES)
134 break;
135 }
136 else if(ctx.tag == X509_EXTENSIONS)
137 {
138 if(certTBS[EXTENSIONS_REF].len != 0)
139 return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
140 certTBS[EXTENSIONS_REF].buf = &ctx.buffer[startOfElement];
141 ctx.offset += length;
142 certTBS[EXTENSIONS_REF].len =
143 (INT16)ctx.offset - startOfElement;
144 }
145 else
146 return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
147 }
148 // Make sure that we used all of the data and found at least the required
149 // number of elements.
150 if((ctx.offset != ctx.size) || (countOfSequences < 3)
151 || (countOfSequences > 4)
152 || (certTBS[EXTENSIONS_REF].buf == 0))
153 return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
154 // Now that we know how many sequences there were, we can put them where they
155 // belong
156 for(i = 0; i < countOfSequences; i++)
157 certTBS[SUBJECT_KEY_REF - i] = partial[countOfSequences - 1 - i];
158
159 // If only three SEQUENCES, then the TPM needs to produce the signature algorithm.
160 // See if it can
161 if((countOfSequences == 3) &&
162 (X509AddSigningAlgorithm(NULL, signKey, &in->inScheme) == 0))
163 return TPM_RCS_SCHEME + RC_CertifyX509_signHandle;
164
165 // Process the extensions
166 result = X509ProcessExtensions(object, &certTBS[EXTENSIONS_REF]);
167 if(result != TPM_RC_SUCCESS)
168 // If the extension has the TPMA_OBJECT extension and the attributes don't
169 // match, then the error code will be TPM_RCS_ATTRIBUTES. Otherwise, the error
170 // indicates a malformed partialCertificate.
171 return result + ((result == TPM_RCS_ATTRIBUTES)
172 ? RC_CertifyX509_objectHandle
173 : RC_CertifyX509_partialCertificate);
174 // Command Output
175 // Create the addedToCertificate values
176
177 // Build the addedToCertificate from the bottom up.
178 // Initialize the context structure
179 ASN1InitialializeMarshalContext(&ctxOut, sizeof(out->addedToCertificate.t.buffer),
180 out->addedToCertificate.t.buffer);
181 // Place a marker for the overall context
182 ASN1StartMarshalContext(&ctxOut); // SEQUENCE for addedToCertificate
183
184 // Add the subject public key descriptor
185 certTBS[SUBJECT_PUBLIC_KEY_REF].len = X509AddPublicKey(&ctxOut, object);
186 certTBS[SUBJECT_PUBLIC_KEY_REF].buf = ctxOut.buffer + ctxOut.offset;
187 // If the caller didn't provide the algorithm identifier, create it
188 if(certTBS[SIGNATURE_REF].len == 0)
189 {
190 certTBS[SIGNATURE_REF].len = X509AddSigningAlgorithm(&ctxOut, signKey,
191 &in->inScheme);
192 certTBS[SIGNATURE_REF].buf = ctxOut.buffer + ctxOut.offset;
193 }
194 // Create the serial number value. Use the out->tbsDigest as scratch.
195 {
196 TPM2B *digest = &out->tbsDigest.b;
197 //
198 digest->size = (INT16)CryptHashStart(&hash, signKey->publicArea.nameAlg);
199 pAssert(digest->size != 0);
200
201 // The serial number size is the smaller of the digest and the vendor-defined
202 // value
203 digest->size = MIN(digest->size, SIZE_OF_X509_SERIAL_NUMBER);
204 // Add all the parts of the certificate other than the serial number
205 // and version number
206 for(i = SIGNATURE_REF; i < REF_COUNT; i++)
207 CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf);
208 // throw in the Name of the signing key...
209 CryptDigestUpdate2B(&hash, &signKey->name.b);
210 // ...and the Name of the signed key.
211 CryptDigestUpdate2B(&hash, &object->name.b);
212 // Done
213 CryptHashEnd2B(&hash, digest);
214 }
215
216 // Add the serial number
217 certTBS[SERIAL_NUMBER_REF].len =
218 ASN1PushInteger(&ctxOut, out->tbsDigest.t.size, out->tbsDigest.t.buffer);
219 certTBS[SERIAL_NUMBER_REF].buf = ctxOut.buffer + ctxOut.offset;
220
221 // Add the static version number
222 ASN1StartMarshalContext(&ctxOut);
223 ASN1PushUINT(&ctxOut, 2);
224 certTBS[VERSION_REF].len =
225 ASN1EndEncapsulation(&ctxOut, ASN1_APPLICAIION_SPECIFIC);
226 certTBS[VERSION_REF].buf = ctxOut.buffer + ctxOut.offset;
227
228 // Create a fake tag and length for the TBS in the space used for
229 // 'addedToCertificate'
230 {
231 for(length = 0, i = 0; i < REF_COUNT; i++)
232 length += certTBS[i].len;
233 // Put a fake tag and length into the buffer for use in the tbsDigest
234 certTBS[ENCODED_SIZE_REF].len =
235 ASN1PushTagAndLength(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE, length);
236 certTBS[ENCODED_SIZE_REF].buf = ctxOut.buffer + ctxOut.offset;
237 // Restore the buffer pointer to add back the number of octets used for the
238 // tag and length
239 ctxOut.offset += certTBS[ENCODED_SIZE_REF].len;
240 }
241 // sanity check
242 if(ctxOut.offset < 0)
243 return TPM_RC_FAILURE;
244 // Create the tbsDigest to sign
245 out->tbsDigest.t.size = CryptHashStart(&hash, in->inScheme.details.any.hashAlg);
246 for(i = 0; i < REF_COUNT; i++)
247 CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf);
248 CryptHashEnd2B(&hash, &out->tbsDigest.b);
249
250 #if CERTIFYX509_DEBUG
251 {
252 BYTE fullTBS[4096];
253 BYTE *fill = fullTBS;
254 int j;
255 for (j = 0; j < REF_COUNT; j++)
256 {
257 MemoryCopy(fill, certTBS[j].buf, certTBS[j].len);
258 fill += certTBS[j].len;
259 }
260 DebugDumpBuffer((int)(fill - &fullTBS[0]), fullTBS, "\nfull TBS");
261 }
262 #endif
263
264 // Finish up the processing of addedToCertificate
265 // Create the actual tag and length for the addedToCertificate structure
266 out->addedToCertificate.t.size =
267 ASN1EndEncapsulation(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE);
268 // Now move all the addedToContext to the start of the buffer
269 MemoryCopy(out->addedToCertificate.t.buffer, ctxOut.buffer + ctxOut.offset,
270 out->addedToCertificate.t.size);
271 #if CERTIFYX509_DEBUG
272 DebugDumpBuffer(out->addedToCertificate.t.size, out->addedToCertificate.t.buffer,
273 "\naddedToCertificate");
274 #endif
275 // only thing missing is the signature
276 result = CryptSign(signKey, &in->inScheme, &out->tbsDigest, &out->signature);
277
278 return result;
279 }
280
281 #endif // CC_CertifyX509
282