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 }