• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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