/src/libtpms/src/tpm2/X509_spt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* X509 Support */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* */ |
7 | | /* Licenses and Notices */ |
8 | | /* */ |
9 | | /* 1. Copyright Licenses: */ |
10 | | /* */ |
11 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
12 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
13 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
14 | | /* derivative works, distribute, display and perform the Source Code and */ |
15 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
16 | | /* */ |
17 | | /* - The TCG rants to the user of the other parts of the specification */ |
18 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
19 | | /* display, and perform the specification solely for the purpose of */ |
20 | | /* developing products based on such documents. */ |
21 | | /* */ |
22 | | /* 2. Source Code Distribution Conditions: */ |
23 | | /* */ |
24 | | /* - Redistributions of Source Code must retain the above copyright licenses, */ |
25 | | /* this list of conditions and the following disclaimers. */ |
26 | | /* */ |
27 | | /* - Redistributions in binary form must reproduce the above copyright */ |
28 | | /* licenses, this list of conditions and the following disclaimers in the */ |
29 | | /* documentation and/or other materials provided with the distribution. */ |
30 | | /* */ |
31 | | /* 3. Disclaimers: */ |
32 | | /* */ |
33 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
34 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
35 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
36 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
37 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
38 | | /* information on specification licensing rights available through TCG */ |
39 | | /* membership agreements. */ |
40 | | /* */ |
41 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
42 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
43 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
44 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
45 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
46 | | /* */ |
47 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
48 | | /* liability, including liability for infringement of any proprietary */ |
49 | | /* rights, relating to use of information in this specification and to the */ |
50 | | /* implementation of this specification, and TCG disclaims all liability for */ |
51 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
52 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
53 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
54 | | /* arising in any way out of use or reliance upon this specification or any */ |
55 | | /* information herein. */ |
56 | | /* */ |
57 | | /* (c) Copyright IBM Corp. and others, 2019 - 2024 */ |
58 | | /* */ |
59 | | /********************************************************************************/ |
60 | | |
61 | | //** Includes |
62 | | #include "Tpm.h" |
63 | | #include "TpmASN1.h" |
64 | | #include "TpmASN1_fp.h" |
65 | | #define _X509_SPT_ |
66 | | #include "X509.h" |
67 | | #include "X509_spt_fp.h" |
68 | | #if ALG_RSA |
69 | | # include "X509_RSA_fp.h" |
70 | | #endif // ALG_RSA |
71 | | #if ALG_ECC |
72 | | # include "X509_ECC_fp.h" |
73 | | #endif // ALG_ECC |
74 | | #if ALG_SM2 |
75 | | //# include "X509_SM2_fp.h" |
76 | | #endif // ALG_RSA |
77 | | |
78 | | #if CC_CertifyX509 |
79 | | |
80 | | //** Unmarshaling Functions |
81 | | |
82 | | //*** X509FindExtensionByOID() |
83 | | // This will search a list of X509 extensions to find an extension with the |
84 | | // requested OID. If the extension is found, the output context ('ctx') is set up |
85 | | // to point to the OID in the extension. |
86 | | // Return Type: BOOL |
87 | | // TRUE(1) success |
88 | | // FALSE(0) failure (could be catastrophic) |
89 | | BOOL X509FindExtensionByOID(ASN1UnmarshalContext* ctxIn, // IN: the context to search |
90 | | ASN1UnmarshalContext* ctx, // OUT: the extension context |
91 | | const BYTE* OID // IN: oid to search for |
92 | | ) |
93 | 0 | { |
94 | 0 | INT16 length; |
95 | | // |
96 | 0 | pAssert(ctxIn != NULL); |
97 | | // Make the search non-destructive of the input if ctx provided. Otherwise, use |
98 | | // the provided context. |
99 | 0 | if(ctx == NULL) |
100 | 0 | ctx = ctxIn; |
101 | | // if the provided search context is different from the context of the extension, |
102 | | // then copy the search context to the search context. |
103 | 0 | else if(ctx != ctxIn) |
104 | 0 | *ctx = *ctxIn; |
105 | | // Now, search in the extension context |
106 | 0 | for(; ctx->size > ctx->offset; ctx->offset += length) |
107 | 0 | { |
108 | 0 | GOTO_ERROR_UNLESS((length = ASN1NextTag(ctx)) >= 0); |
109 | | // If this is not a constructed sequence, then it doesn't belong |
110 | | // in the extensions. |
111 | 0 | GOTO_ERROR_UNLESS(ctx->tag == ASN1_CONSTRUCTED_SEQUENCE); |
112 | | // Make sure that this entry could hold the OID |
113 | 0 | if(length >= OID_SIZE(OID)) |
114 | 0 | { |
115 | | // See if this is a match for the provided object identifier. |
116 | 0 | if(MemoryEqual(OID, &(ctx->buffer[ctx->offset]), OID_SIZE(OID))) |
117 | 0 | { |
118 | | // Return with ' ctx' set to point to the start of the OID with the size |
119 | | // set to be the size of the SEQUENCE |
120 | 0 | ctx->buffer += ctx->offset; |
121 | 0 | ctx->offset = 0; |
122 | 0 | ctx->size = length; |
123 | 0 | return TRUE; |
124 | 0 | } |
125 | 0 | } |
126 | 0 | } |
127 | 0 | GOTO_ERROR_UNLESS(ctx->offset == ctx->size); |
128 | 0 | return FALSE; |
129 | 0 | Error: |
130 | 0 | ctxIn->size = -1; |
131 | 0 | ctx->size = -1; |
132 | 0 | return FALSE; |
133 | 0 | } |
134 | | |
135 | | //*** X509GetExtensionBits() |
136 | | // This function will extract a bit field from an extension. If the extension doesn't |
137 | | // contain a bit string, it will fail. |
138 | | // Return Type: BOOL |
139 | | // TRUE(1) success |
140 | | // FALSE(0) failure |
141 | | UINT32 |
142 | | X509GetExtensionBits(ASN1UnmarshalContext* ctx, UINT32* value) |
143 | 0 | { |
144 | 0 | INT16 length; |
145 | | // |
146 | 0 | while(((length = ASN1NextTag(ctx)) > 0) && (ctx->size > ctx->offset)) |
147 | 0 | { |
148 | | // Since this is an extension, the extension value will be in an OCTET STRING |
149 | 0 | if(ctx->tag == ASN1_OCTET_STRING) |
150 | 0 | { |
151 | 0 | return ASN1GetBitStringValue(ctx, value); |
152 | 0 | } |
153 | 0 | ctx->offset += length; |
154 | 0 | } |
155 | 0 | ctx->size = -1; |
156 | 0 | return FALSE; |
157 | 0 | } |
158 | | |
159 | | //***X509ProcessExtensions() |
160 | | // This function is used to process the TPMA_OBJECT and KeyUsage extensions. It is not |
161 | | // in the CertifyX509.c code because it makes the code harder to follow. |
162 | | // Return Type: TPM_RC |
163 | | // TPM_RCS_ATTRIBUTES the attributes of object are not consistent with |
164 | | // the extension setting |
165 | | // TPM_RC_VALUE problem parsing the extensions |
166 | | TPM_RC |
167 | | X509ProcessExtensions( |
168 | | OBJECT* object, // IN: The object with the attributes to |
169 | | // check |
170 | | stringRef* extension // IN: The start and length of the extensions |
171 | | ) |
172 | 0 | { |
173 | 0 | ASN1UnmarshalContext ctx; |
174 | 0 | ASN1UnmarshalContext extensionCtx; |
175 | 0 | INT16 length; |
176 | 0 | UINT32 value; |
177 | 0 | TPMA_OBJECT attributes = object->publicArea.objectAttributes; |
178 | | // |
179 | 0 | if(!ASN1UnmarshalContextInitialize(&ctx, extension->len, extension->buf) |
180 | 0 | || ((length = ASN1NextTag(&ctx)) < 0) || (ctx.tag != X509_EXTENSIONS)) |
181 | 0 | return TPM_RCS_VALUE; |
182 | 0 | if(((length = ASN1NextTag(&ctx)) < 0) || (ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE))) |
183 | 0 | return TPM_RCS_VALUE; |
184 | | |
185 | | // Get the extension for the TPMA_OBJECT if there is one |
186 | 0 | if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_TCG_TPMA_OBJECT) |
187 | 0 | && X509GetExtensionBits(&extensionCtx, &value)) |
188 | 0 | { |
189 | | // If an keyAttributes extension was found, it must be exactly the same as the |
190 | | // attributes of the object. |
191 | | // NOTE: MemoryEqual() is used rather than a simple UINT32 compare to avoid |
192 | | // type-punned pointer warning/error. |
193 | 0 | if(!MemoryEqual(&value, &attributes, sizeof(value))) |
194 | 0 | return TPM_RCS_ATTRIBUTES; |
195 | 0 | } |
196 | | // Make sure the failure to find the value wasn't because of a fatal error |
197 | 0 | else if(extensionCtx.size < 0) |
198 | 0 | return TPM_RCS_VALUE; |
199 | | |
200 | | // Get the keyUsage extension. This one is required |
201 | 0 | if(X509FindExtensionByOID(&ctx, &extensionCtx, OID_KEY_USAGE_EXTENSION) |
202 | 0 | && X509GetExtensionBits(&extensionCtx, &value)) |
203 | 0 | { |
204 | 0 | x509KeyUsageUnion keyUsage; |
205 | 0 | BOOL badSign; |
206 | 0 | BOOL badDecrypt; |
207 | 0 | BOOL badFixedTPM; |
208 | 0 | BOOL badRestricted; |
209 | | |
210 | | // |
211 | 0 | keyUsage.integer = value; |
212 | | // see if any reserved bits are set |
213 | 0 | if(keyUsage.integer & ~(TPMA_X509_KEY_USAGE_ALLOWED_BITS)) |
214 | 0 | return TPM_RCS_RESERVED_BITS; // For KeyUsage: |
215 | | // 1) 'sign' is SET if Key Usage includes signing |
216 | 0 | badSign = ((KEY_USAGE_SIGN.integer & keyUsage.integer) != 0) |
217 | 0 | && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign); |
218 | | // 2) 'decrypt' is SET if Key Usage includes decryption uses |
219 | 0 | badDecrypt = ((KEY_USAGE_DECRYPT.integer & keyUsage.integer) != 0) |
220 | 0 | && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt); |
221 | | // 3) 'fixedTPM' is SET if Key Usage is non-repudiation |
222 | 0 | badFixedTPM = IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE, nonrepudiation) |
223 | 0 | && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM); |
224 | | // 4)'restricted' is SET if Key Usage is for key encipherment. |
225 | 0 | badRestricted = |
226 | 0 | IS_ATTRIBUTE(keyUsage.x509, TPMA_X509_KEY_USAGE, keyEncipherment) |
227 | 0 | && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted); |
228 | 0 | if(badSign || badDecrypt || badFixedTPM || badRestricted) |
229 | 0 | return TPM_RCS_VALUE; |
230 | 0 | } |
231 | 0 | else |
232 | | // The KeyUsage extension is required |
233 | 0 | return TPM_RCS_VALUE; |
234 | | |
235 | 0 | return TPM_RC_SUCCESS; |
236 | 0 | } |
237 | | |
238 | | //** Marshaling Functions |
239 | | |
240 | | //*** X509AddSigningAlgorithm() |
241 | | // This creates the singing algorithm data. |
242 | | // Return Type: INT16 |
243 | | // > 0 number of octets added |
244 | | // <= 0 failure |
245 | | INT16 |
246 | | X509AddSigningAlgorithm( |
247 | | ASN1MarshalContext* ctx, OBJECT* signKey, TPMT_SIG_SCHEME* scheme) |
248 | 0 | { |
249 | 0 | switch(signKey->publicArea.type) |
250 | 0 | { |
251 | 0 | # if ALG_RSA |
252 | 0 | case TPM_ALG_RSA: |
253 | 0 | return X509AddSigningAlgorithmRSA(signKey, scheme, ctx); |
254 | 0 | # endif // ALG_RSA |
255 | 0 | # if ALG_ECC |
256 | 0 | case TPM_ALG_ECC: |
257 | 0 | return X509AddSigningAlgorithmECC(signKey, scheme, ctx); |
258 | 0 | # endif // ALG_ECC |
259 | 0 | # if ALG_SM2 |
260 | 0 | case TPM_ALG_SM2: |
261 | 0 | break; // no signing algorithm for SM2 yet |
262 | | // return X509AddSigningAlgorithmSM2(signKey, scheme, ctx); |
263 | 0 | # endif // ALG_SM2 |
264 | 0 | default: |
265 | 0 | break; |
266 | 0 | } |
267 | 0 | return 0; |
268 | 0 | } |
269 | | |
270 | | //*** X509AddPublicKey() |
271 | | // This function will add the publicKey description to the DER data. If fillPtr is |
272 | | // NULL, then no data is transferred and this function will indicate if the TPM |
273 | | // has the values for DER-encoding of the public key. |
274 | | // Return Type: INT16 |
275 | | // > 0 number of octets added |
276 | | // == 0 failure |
277 | | INT16 |
278 | | X509AddPublicKey(ASN1MarshalContext* ctx, OBJECT* object) |
279 | 0 | { |
280 | 0 | switch(object->publicArea.type) |
281 | 0 | { |
282 | 0 | # if ALG_RSA |
283 | 0 | case TPM_ALG_RSA: |
284 | 0 | return X509AddPublicRSA(object, ctx); |
285 | 0 | # endif |
286 | 0 | # if ALG_ECC |
287 | 0 | case TPM_ALG_ECC: |
288 | 0 | return X509AddPublicECC(object, ctx); |
289 | 0 | # endif |
290 | 0 | # if ALG_SM2 |
291 | 0 | case TPM_ALG_SM2: |
292 | 0 | break; |
293 | 0 | # endif |
294 | 0 | default: |
295 | 0 | break; |
296 | 0 | } |
297 | 0 | return FALSE; |
298 | 0 | } |
299 | | |
300 | | //*** X509PushAlgorithmIdentifierSequence() |
301 | | // The function adds the algorithm identifier sequence. |
302 | | // Return Type: INT16 |
303 | | // > 0 number of bytes added |
304 | | // == 0 failure |
305 | | INT16 |
306 | | X509PushAlgorithmIdentifierSequence(ASN1MarshalContext* ctx, const BYTE* OID) |
307 | 0 | { |
308 | | // An algorithm ID sequence is: |
309 | | // SEQUENCE |
310 | | // OID |
311 | | // NULL |
312 | 0 | ASN1StartMarshalContext(ctx); // hash algorithm |
313 | 0 | ASN1PushNull(ctx); |
314 | 0 | ASN1PushOID(ctx, OID); |
315 | 0 | return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); |
316 | 0 | } |
317 | | |
318 | | #endif // CC_CertifyX509 |