• 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 //** Includes
36 #include "Tpm.h"
37 #include "TpmASN1.h"
38 #include "TpmASN1_fp.h"
39 #define _X509_SPT_
40 #include "X509.h"
41 #include "X509_spt_fp.h"
42 #if ALG_RSA
43 #   include "X509_RSA_fp.h"
44 #endif // ALG_RSA
45 #if ALG_ECC
46 #   include "X509_ECC_fp.h"
47 #endif // ALG_ECC
48 #if ALG_SM2
49 //#   include "X509_SM2_fp.h"
50 #endif // ALG_RSA
51 
52 
53 
54 //** Unmarshaling Functions
55 
56 //*** X509FindExtensionByOID()
57 // This will search a list of X509 extensions to find an extension with the
58 // requested OID. If the extension is found, the output context ('ctx') is set up
59 // to point to the OID in the extension.
60 //  Return Type: BOOL
61 //      TRUE(1)         success
62 //      FALSE(0)        failure (could be catastrophic)
63 BOOL
X509FindExtensionByOID(ASN1UnmarshalContext * ctxIn,ASN1UnmarshalContext * ctx,const BYTE * OID)64 X509FindExtensionByOID(
65     ASN1UnmarshalContext    *ctxIn,         // IN: the context to search
66     ASN1UnmarshalContext    *ctx,           // OUT: the extension context
67     const BYTE              *OID            // IN: oid to search for
68 )
69 {
70     INT16                length;
71 //
72     pAssert(ctxIn != NULL);
73     // Make the search non-destructive of the input if ctx provided. Otherwise, use
74     // the provided context.
75     if (ctx == NULL)
76         ctx = ctxIn;
77     // if the provided search context is different from the context of the extension,
78     // then copy the search context to the search context.
79     else if(ctx != ctxIn)
80         *ctx = *ctxIn;
81     // Now, search in the extension context
82     for(;ctx->size > ctx->offset; ctx->offset += length)
83     {
84         VERIFY((length = ASN1NextTag(ctx)) >= 0);
85         // If this is not a constructed sequence, then it doesn't belong
86         // in the extensions.
87         VERIFY(ctx->tag == ASN1_CONSTRUCTED_SEQUENCE);
88         // Make sure that this entry could hold the OID
89         if (length >= OID_SIZE(OID))
90         {
91             // See if this is a match for the provided object identifier.
92             if (MemoryEqual(OID, &(ctx->buffer[ctx->offset]), OID_SIZE(OID)))
93             {
94                 // Return with ' ctx' set to point to the start of the OID with the size
95                 // set to be the size of the SEQUENCE
96                 ctx->buffer += ctx->offset;
97                 ctx->offset = 0;
98                 ctx->size = length;
99                 return TRUE;
100             }
101         }
102     }
103     VERIFY(ctx->offset == ctx->size);
104     return FALSE;
105 Error:
106     ctxIn->size = -1;
107     ctx->size = -1;
108     return FALSE;
109 }
110 
111 //*** X509GetExtensionBits()
112 // This function will extract a bit field from an extension. If the extension doesn't
113 // contain a bit string, it will fail.
114 // Return Type: BOOL
115 //  TRUE(1)         success
116 //  FALSE(0)        failure
117 UINT32
X509GetExtensionBits(ASN1UnmarshalContext * ctx,UINT32 * value)118 X509GetExtensionBits(
119     ASN1UnmarshalContext            *ctx,
120     UINT32                          *value
121 )
122 {
123     INT16                length;
124 //
125     while (((length = ASN1NextTag(ctx)) > 0) && (ctx->size > ctx->offset))
126     {
127         // Since this is an extension, the extension value will be in an OCTET STRING
128         if (ctx->tag == ASN1_OCTET_STRING)
129         {
130             return ASN1GetBitStringValue(ctx, value);
131         }
132         ctx->offset += length;
133     }
134     ctx->size = -1;
135     return FALSE;
136 }
137 
138 //***X509ProcessExtensions()
139 // This function is used to process the TPMA_OBJECT and KeyUsage extensions. It is not
140 // in the CertifyX509.c code because it makes the code harder to follow.
141 // Return Type: TPM_RC
142 //      TPM_RCS_ATTRIBUTES      the attributes of object are not consistent with
143 //                              the extension setting
144 //      TPM_RC_VALUE            problem parsing the extensions
145 TPM_RC
X509ProcessExtensions(OBJECT * object,stringRef * extension)146 X509ProcessExtensions(
147     OBJECT              *object,        // IN: The object with the attributes to
148                                         //      check
149     stringRef           *extension      // IN: The start and length of the extensions
150 )
151 {
152     ASN1UnmarshalContext     ctx;
153     ASN1UnmarshalContext     extensionCtx;
154     INT16                    length;
155     UINT32                   value;
156     TPMA_OBJECT              attributes = object->publicArea.objectAttributes;
157 //
158     if(!ASN1UnmarshalContextInitialize(&ctx, extension->len, extension->buf)
159        || ((length = ASN1NextTag(&ctx)) < 0)
160        || (ctx.tag != X509_EXTENSIONS))
161         return TPM_RCS_VALUE;
162     if( ((length = ASN1NextTag(&ctx)) < 0)
163        || (ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE)))
164         return TPM_RCS_VALUE;
165 
166     // Get the extension for the TPMA_OBJECT if there is one
167     if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_TCG_TPMA_OBJECT) &&
168         X509GetExtensionBits(&extensionCtx, &value))
169     {
170         // If an keyAttributes extension was found, it must be exactly the same as the
171         // attributes of the object.
172         // NOTE: MemoryEqual() is used rather than a simple UINT32 compare to avoid
173         // type-punned pointer warning/error.
174         if(!MemoryEqual(&value, &attributes, sizeof(value)))
175             return TPM_RCS_ATTRIBUTES;
176     }
177     // Make sure the failure to find the value wasn't because of a fatal error
178     else if(extensionCtx.size < 0)
179         return TPM_RCS_VALUE;
180 
181     // Get the keyUsage extension. This one is required
182     if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_KEY_USAGE_EXTENSION) &&
183         X509GetExtensionBits(&extensionCtx, &value))
184     {
185         x509KeyUsageUnion   keyUsage;
186         BOOL                badSign;
187         BOOL                badDecrypt;
188         BOOL                badFixedTPM;
189         BOOL                badRestricted;
190 
191     //
192         keyUsage.integer = value;
193         // For KeyUsage:
194         // 1) 'sign' is SET if Key Usage includes signing
195         badSign = ((KEY_USAGE_SIGN.integer & keyUsage.integer) != 0)
196               && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign);
197         // 2) 'decrypt' is SET if Key Usage includes decryption uses
198         badDecrypt = ((KEY_USAGE_DECRYPT.integer & keyUsage.integer) != 0)
199                      && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt);
200         // 3) 'fixedTPM' is SET if Key Usage is non-repudiation
201         badFixedTPM = IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE,
202                                      nonrepudiation)
203                       && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM);
204         // 4)'restricted' is SET if Key Usage is for key agreement.
205         badRestricted = IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE, keyAgreement)
206                      && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted);
207         if(badSign || badDecrypt || badFixedTPM || badRestricted)
208             return TPM_RCS_VALUE;
209     }
210     else
211         // The KeyUsage extension is required
212         return TPM_RCS_VALUE;
213 
214     return TPM_RC_SUCCESS;
215 }
216 
217 //** Marshaling Functions
218 
219 //*** X509AddSigningAlgorithm()
220 // This creates the singing algorithm data.
221 // Return Type: INT16
222 //  > 0                 number of octets added
223 // <= 0                 failure
224 INT16
X509AddSigningAlgorithm(ASN1MarshalContext * ctx,OBJECT * signKey,TPMT_SIG_SCHEME * scheme)225 X509AddSigningAlgorithm(
226     ASN1MarshalContext  *ctx,
227     OBJECT              *signKey,
228     TPMT_SIG_SCHEME     *scheme
229 )
230 {
231     switch(signKey->publicArea.type)
232     {
233 #if ALG_RSA
234         case TPM_ALG_RSA:
235             return X509AddSigningAlgorithmRSA(signKey, scheme, ctx);
236 #endif // ALG_RSA
237 #if ALG_ECC
238         case TPM_ALG_ECC:
239             return X509AddSigningAlgorithmECC(signKey, scheme, ctx);
240 #endif // ALG_ECC
241 #if ALG_SM2
242         case TPM_ALG_SM2:
243             break;  // no signing algorithm for SM2 yet
244 //            return X509AddSigningAlgorithmSM2(signKey, scheme, ctx);
245 #endif // ALG_SM2
246         default:
247             break;
248     }
249     return 0;
250 }
251 
252 //*** X509AddPublicKey()
253 // This function will add the publicKey description to the DER data. If fillPtr is
254 // NULL, then no data is transferred and this function will indicate if the TPM
255 // has the values for DER-encoding of the public key.
256 //  Return Type: INT16
257 //      > 0         number of octets added
258 //      == 0        failure
259 INT16
X509AddPublicKey(ASN1MarshalContext * ctx,OBJECT * object)260 X509AddPublicKey(
261     ASN1MarshalContext  *ctx,
262     OBJECT              *object
263 )
264 {
265     switch(object->publicArea.type)
266     {
267 #if ALG_RSA
268         case TPM_ALG_RSA:
269             return X509AddPublicRSA(object, ctx);
270 #endif
271 #if ALG_ECC
272         case TPM_ALG_ECC:
273             return X509AddPublicECC(object, ctx);
274 #endif
275 #if ALG_SM2
276         case TPM_ALG_SM2:
277             break;
278 #endif
279         default:
280             break;
281     }
282     return FALSE;
283 }
284 
285 
286 //*** X509PushAlgorithmIdentifierSequence()
287 // The function adds the algorithm identifier sequence.
288 //  Return Type: INT16
289 //      > 0         number of bytes added
290 //     == 0         failure
291 INT16
X509PushAlgorithmIdentifierSequence(ASN1MarshalContext * ctx,const BYTE * OID)292 X509PushAlgorithmIdentifierSequence(
293     ASN1MarshalContext          *ctx,
294     const BYTE                  *OID
295     )
296 {
297     // An algorithm ID sequence is:
298     //  SEQUENCE
299     //      OID
300     //      NULL
301     ASN1StartMarshalContext(ctx);   // hash algorithm
302     ASN1PushNull(ctx);
303     ASN1PushOID(ctx, OID);
304     return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE);
305 }