Coverage Report

Created: 2025-07-11 06:08

/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