• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / libtpms / 2735

pending completion
2735

cron

travis-ci-com

stefanberger
tpm2: rev164: Synchronize _TPM_Init() with upstream

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

1 of 1 new or added line in 1 file covered. (100.0%)

33726 of 44191 relevant lines covered (76.32%)

93553.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.66
/src/tpm2/CryptUtil.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                        Interfaces to the Crypto Engine                                */
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 grants 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, 2016 - 2023                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
/* 10.2.6 CryptUtil.c */
62
/* 10.2.6.1 Introduction */
63
/* This module contains the interfaces to the CryptoEngine() and provides miscellaneous
64
   cryptographic functions in support of the TPM. */
65
/* 10.2.6.2 Includes */
66
#include "Tpm.h"
67
/* 10.2.6.3 Hash/HMAC Functions */
68
/* 10.2.6.3.1 CryptHmacSign() */
69
/* Sign a digest using an HMAC key. This an HMAC of a digest, not an HMAC of a message. */
70
/* Error Returns Meaning */
71
/* TPM_RC_HASH not a valid hash */
72
static TPM_RC
73
CryptHmacSign(
48✔
74
              TPMT_SIGNATURE      *signature,     // OUT: signature
75
              OBJECT              *signKey,       // IN: HMAC key sign the hash
76
              TPM2B_DIGEST        *hashData       // IN: hash to be signed
77
              )
78
{
79
    HMAC_STATE       hmacState;
48✔
80
    UINT32           digestSize;
48✔
81
    digestSize = CryptHmacStart2B(&hmacState, signature->signature.any.hashAlg,
96✔
82
                                  &signKey->sensitive.sensitive.bits.b);
48✔
83
    CryptDigestUpdate2B(&hmacState.hashState, &hashData->b);
48✔
84
    CryptHmacEnd(&hmacState, digestSize,
48✔
85
                 (BYTE *)&signature->signature.hmac.digest);
48✔
86
    return TPM_RC_SUCCESS;
48✔
87
}
88
/* 10.2.6.3.2 CryptHMACVerifySignature() */
89
/* This function will verify a signature signed by a HMAC key. Note that a caller needs to prepare
90
   signature with the signature algorithm (TPM_ALG_HMAC) and the hash algorithm to use. This
91
   function then builds a signature of that type. */
92
/* Error Returns Meaning */
93
/* TPM_RC_SCHEME not the proper scheme for this key type */
94
/* TPM_RC_SIGNATURE if invalid input or signature is not genuine */
95
static TPM_RC
96
CryptHMACVerifySignature(
20✔
97
                         OBJECT              *signKey,       // IN: HMAC key signed the hash
98
                         TPM2B_DIGEST        *hashData,      // IN: digest being verified
99
                         TPMT_SIGNATURE      *signature      // IN: signature to be verified
100
                         )
101
{
102
    TPMT_SIGNATURE           test;
20✔
103
    TPMT_KEYEDHASH_SCHEME   *keyScheme =
20✔
104
        &signKey->publicArea.parameters.keyedHashDetail.scheme;
105
    //
106
    if((signature->sigAlg != TPM_ALG_HMAC)
20✔
107
       || (signature->signature.hmac.hashAlg == TPM_ALG_NULL))
20✔
108
        return TPM_RC_SCHEME;
109
    // This check is not really needed for verification purposes. However, it does
110
    // prevent someone from trying to validate a signature using a weaker hash
111
    // algorithm than otherwise allowed by the key. That is, a key with a scheme
112
    // other than TMP_ALG_NULL can only be used to validate signatures that have
113
    // a matching scheme.
114
    if((keyScheme->scheme != TPM_ALG_NULL)
20✔
115
       && ((keyScheme->scheme != signature->sigAlg)
20✔
116
           || (keyScheme->details.hmac.hashAlg != signature->signature.any.hashAlg)))
20✔
117
        return TPM_RC_SIGNATURE;
118
    test.sigAlg = signature->sigAlg;
20✔
119
    test.signature.hmac.hashAlg = signature->signature.hmac.hashAlg;
20✔
120
    CryptHmacSign(&test, signKey, hashData);
20✔
121
    // Compare digest
122
    if(!MemoryEqual(&test.signature.hmac.digest,
20✔
123
                    &signature->signature.hmac.digest,
20✔
124
                    CryptHashGetDigestSize(signature->signature.any.hashAlg)))
20✔
125
        return TPM_RC_SIGNATURE;
×
126
    return TPM_RC_SUCCESS;
127
}
128
/* 10.2.6.3.3 CryptGenerateKeyedHash() */
129
/* This function creates a keyedHash object. */
130
/* Error Returns Meaning */
131
/* TPM_RC_NO_RESULT cannot get values from random number generator */
132
/* TPM_RC_SIZE sensitive data size is larger than allowed for the scheme */
133
static TPM_RC
134
CryptGenerateKeyedHash(
57✔
135
                       TPMT_PUBLIC             *publicArea,        // IN/OUT: the public area template
136
                       //     for the new key.
137
                       TPMT_SENSITIVE          *sensitive,         // OUT: sensitive area
138
                       TPMS_SENSITIVE_CREATE   *sensitiveCreate,   // IN: sensitive creation data
139
                       RAND_STATE              *rand               // IN: "entropy" source
140
                       )
141
{
142
    TPMT_KEYEDHASH_SCHEME   *scheme;
57✔
143
    TPM_ALG_ID               hashAlg;
57✔
144
    UINT16                   digestSize;
57✔
145
    
146
    scheme = &publicArea->parameters.keyedHashDetail.scheme;
57✔
147
    
148
    if(publicArea->type != TPM_ALG_KEYEDHASH)
57✔
149
        return TPM_RC_FAILURE;
150
    // Pick the limiting hash algorithm
151
    if(scheme->scheme == TPM_ALG_NULL)
57✔
152
        hashAlg = publicArea->nameAlg;
22✔
153
    else if(scheme->scheme == TPM_ALG_XOR)
35✔
154
        hashAlg = scheme->details.xorr.hashAlg;
3✔
155
    else
156
        hashAlg = scheme->details.hmac.hashAlg;
32✔
157
    /* hashBlockSize = CryptHashGetBlockSize(hashAlg); */
158
    digestSize = CryptHashGetDigestSize(hashAlg);
57✔
159
    
160
    // if this is a signing or a decryption key, then the limit
161
    // for the data size is the block size of the hash. This limit
162
    // is set because larger values have lower entropy because of the
163
    // HMAC function. The lower limit is 1/2 the size of the digest
164
    //
165
    //If the user provided the key, check that it is a proper size
166
    if(sensitiveCreate->data.t.size != 0)
57✔
167
        {
168
            if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
26✔
169
               || IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
26✔
170
                {
171
                    if(sensitiveCreate->data.t.size > CryptHashGetBlockSize(hashAlg))
4✔
172
                        return TPM_RC_SIZE;
173
#if 0   // May make this a FIPS-mode requirement
174
                    if(sensitiveCreate->data.t.size < (digestSize / 2))
175
                        return TPM_RC_SIZE;
176
#endif
177
                }
178
            // If this is a data blob, then anything that will get past the unmarshaling
179
            // is OK
180
            MemoryCopy2B(&sensitive->sensitive.bits.b, &sensitiveCreate->data.b,
26✔
181
                         sizeof(sensitive->sensitive.bits.t.buffer));
182
        }
183
    else
184
        {
185
            // The TPM is going to generate the data so set the size to be the
186
            // size of the digest of the algorithm
187
            sensitive->sensitive.bits.t.size =
62✔
188
                DRBG_Generate(rand, sensitive->sensitive.bits.t.buffer, digestSize);
31✔
189
            if(sensitive->sensitive.bits.t.size == 0)
31✔
190
                return (g_inFailureMode) ? TPM_RC_FAILURE : TPM_RC_NO_RESULT;
×
191
        }
192
    return TPM_RC_SUCCESS;
193
}
194
/* 10.2.6.3.4 CryptIsSchemeAnonymous() */
195
/* This function is used to test a scheme to see if it is an anonymous scheme The only anonymous
196
   scheme is ECDAA. ECDAA can be used to do things like U-Prove. */
197
BOOL
198
CryptIsSchemeAnonymous(
862✔
199
                       TPM_ALG_ID       scheme         // IN: the scheme algorithm to test
200
                       )
201
{
202
    return scheme == TPM_ALG_ECDAA;
862✔
203
}
204
/* 10.2.6.4 Symmetric Functions */
205
/* 10.2.6.4.1 ParmDecryptSym() */
206
/* This function performs parameter decryption using symmetric block cipher. */
207
void
208
ParmDecryptSym(
61✔
209
               TPM_ALG_ID       symAlg,        // IN: the symmetric algorithm
210
               TPM_ALG_ID       hash,          // IN: hash algorithm for KDFa
211
               UINT16           keySizeInBits, // IN: the key size in bits
212
               TPM2B           *key,           // IN: KDF HMAC key
213
               TPM2B           *nonceCaller,   // IN: nonce caller
214
               TPM2B           *nonceTpm,      // IN: nonce TPM
215
               UINT32           dataSize,      // IN: size of parameter buffer
216
               BYTE            *data           // OUT: buffer to be decrypted
217
               )
218
{
219
    // KDF output buffer
220
    // It contains parameters for the CFB encryption
221
    // From MSB to LSB, they are the key and iv
222
    BYTE             symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
61✔
223
    // Symmetric key size in byte
224
    UINT16           keySize = (keySizeInBits + 7) / 8;
61✔
225
    TPM2B_IV         iv;
61✔
226
    iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits);
61✔
227
    // If there is decryption to do...
228
    if(iv.t.size > 0)
61✔
229
        {
230
            // Generate key and iv
231
            CryptKDFa(hash, key, CFB_KEY, nonceCaller, nonceTpm,
61✔
232
                      keySizeInBits + (iv.t.size * 8), symParmString, NULL, FALSE);
61✔
233
            MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size);
61✔
234
            CryptSymmetricDecrypt(data, symAlg, keySizeInBits, symParmString,
61✔
235
                                  &iv, TPM_ALG_CFB, dataSize, data);
236
        }
237
    return;
61✔
238
}
239
/* 10.2.6.4.2 ParmEncryptSym() */
240
/* This function performs parameter encryption using symmetric block cipher. */
241
void
242
ParmEncryptSym(
61✔
243
               TPM_ALG_ID       symAlg,        // IN: symmetric algorithm
244
               TPM_ALG_ID       hash,          // IN: hash algorithm for KDFa
245
               UINT16           keySizeInBits, // IN: AES symmetric key size in bits
246
               TPM2B           *key,           // IN: KDF HMAC key
247
               TPM2B           *nonceCaller,   // IN: nonce caller
248
               TPM2B           *nonceTpm,      // IN: nonce TPM
249
               UINT32           dataSize,      // IN: size of parameter buffer
250
               BYTE            *data           // OUT: buffer to be encrypted
251
               )
252
{
253
    // KDF output buffer
254
    // It contains parameters for the CFB encryption
255
    BYTE             symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];
61✔
256
    // Symmetric key size in bytes
257
    UINT16           keySize = (keySizeInBits + 7) / 8;
61✔
258
    TPM2B_IV         iv;
61✔
259
    iv.t.size = CryptGetSymmetricBlockSize(symAlg, keySizeInBits);
61✔
260
    // See if there is any encryption to do
261
    if(iv.t.size > 0)
61✔
262
        {
263
            // Generate key and iv
264
            CryptKDFa(hash, key, CFB_KEY, nonceTpm, nonceCaller,
61✔
265
                      keySizeInBits + (iv.t.size * 8), symParmString, NULL, FALSE);
61✔
266
            MemoryCopy(iv.t.buffer, &symParmString[keySize], iv.t.size);
61✔
267
            CryptSymmetricEncrypt(data, symAlg, keySizeInBits, symParmString, &iv,
61✔
268
                                  TPM_ALG_CFB, dataSize, data);
269
        }
270
    return;
61✔
271
}
272
/* 10.2.6.4.3 CryptGenerateKeySymmetric() */
273
/* This function generates a symmetric cipher key. The derivation process is determined by the type
274
   of the provided rand */
275
/* Error Returns Meaning */
276
/* TPM_RC_NO_RESULT cannot get a random value */
277
/* TPM_RC_KEY_SIZE key size in the public area does not match the size in the sensitive creation
278
   area */
279
/* TPM_RC_KEY provided key value is not allowed */
280
static TPM_RC
281
CryptGenerateKeySymmetric(
35✔
282
                          TPMT_PUBLIC             *publicArea,        // IN/OUT: The public area template
283
                          //     for the new key.
284
                          TPMT_SENSITIVE          *sensitive,         // OUT: sensitive area
285
                          TPMS_SENSITIVE_CREATE   *sensitiveCreate,   // IN: sensitive creation data
286
                          RAND_STATE              *rand               // IN: the "entropy" source for
287
                          )
288
{
289
    UINT16           keyBits = publicArea->parameters.symDetail.sym.keyBits.sym;
35✔
290
    TPM_RC           result;
35✔
291
    //
292
    // only do multiples of RADIX_BITS
293
    if((keyBits % RADIX_BITS) != 0)
35✔
294
        return TPM_RC_KEY_SIZE;
295
    // If this is not a new key, then the provided key data must be the right size
296
    if(sensitiveCreate->data.t.size != 0)
35✔
297
        {
298
            result = CryptSymKeyValidate(&publicArea->parameters.symDetail.sym,
×
299
                                         (TPM2B_SYM_KEY *)&sensitiveCreate->data);
×
300
            if(result == TPM_RC_SUCCESS)
×
301
                MemoryCopy2B(&sensitive->sensitive.sym.b, &sensitiveCreate->data.b,
×
302
                             sizeof(sensitive->sensitive.sym.t.buffer));
303
        }
304
#if ALG_TDES
305
    else if(publicArea->parameters.symDetail.sym.algorithm == TPM_ALG_TDES)
35✔
306
        {
307
            sensitive->sensitive.sym.t.size = keyBits / 8;
3✔
308
            result = CryptGenerateKeyDes(publicArea, sensitive, rand);
3✔
309
        }
310
#endif
311
    else
312
    {
313
        sensitive->sensitive.sym.t.size =
64✔
314
            DRBG_Generate(rand, sensitive->sensitive.sym.t.buffer,
32✔
315
                          BITS_TO_BYTES(keyBits));
32✔
316
        if(g_inFailureMode)
32✔
317
            result = TPM_RC_FAILURE;
318
        else if(sensitive->sensitive.sym.t.size == 0)
32✔
319
            result = TPM_RC_NO_RESULT;
320
        else
321
            result = TPM_RC_SUCCESS;
32✔
322
    }
323
    return result;
324
}
325
/* 10.2.6.4.4 CryptXORObfuscation() */
326
/* This function implements XOR obfuscation. It should not be called if the hash algorithm is not
327
   implemented. The only return value from this function is TPM_RC_SUCCESS. */
328
void
329
CryptXORObfuscation(
179✔
330
                    TPM_ALG_ID       hash,          // IN: hash algorithm for KDF
331
                    TPM2B           *key,           // IN: KDF key
332
                    TPM2B           *contextU,      // IN: contextU
333
                    TPM2B           *contextV,      // IN: contextV
334
                    UINT32           dataSize,      // IN: size of data buffer
335
                    BYTE            *data           // IN/OUT: data to be XORed in place
336
                    )
337
{
338
    BYTE             mask[MAX_DIGEST_SIZE]; // Allocate a digest sized buffer
179✔
339
    BYTE            *pm;
179✔
340
    UINT32           i;
179✔
341
    UINT32           counter = 0;
179✔
342
    UINT16           hLen = CryptHashGetDigestSize(hash);
179✔
343
    UINT32           requestSize = dataSize * 8;
179✔
344
    INT32            remainBytes = (INT32)dataSize;
179✔
345
    pAssert((key != NULL) && (data != NULL) && (hLen != 0));
179✔
346
    // Call KDFa to generate XOR mask
347
    for(; remainBytes > 0; remainBytes -= hLen)
727✔
348
        {
349
            // Make a call to KDFa to get next iteration
350
            CryptKDFa(hash, key, XOR_KEY, contextU, contextV,
548✔
351
                      requestSize, mask, &counter, TRUE);
352
            // XOR next piece of the data
353
            pm = mask;
548✔
354
            for(i = hLen < remainBytes ? hLen : remainBytes; i > 0; i--)
14,230✔
355
                *data++ ^= *pm++;
13,682✔
356
        }
357
    return;
179✔
358
}
359
/* 10.2.6.5 Initialization and shut down */
360
/* 10.2.6.5.1 CryptInit() */
361
/* This function is called when the TPM receives a _TPM_Init() indication. */
362
/* NOTE: The hash algorithms do not have to be tested, they just need to be available. They have to
363
   be tested before the TPM can accept HMAC authorization or return any result that relies on a hash
364
   algorithm. */
365
/* Return Values Meaning */
366
/* TRUE initializations succeeded */
367
/* FALSE initialization failed and caller should place the TPM into Failure Mode */
368
BOOL
369
CryptInit(
12,212✔
370
          void
371
          )
372
{
373
    BOOL         ok;
12,212✔
374
    // Initialize the vector of implemented algorithms
375
    AlgorithmGetImplementedVector(&g_implementedAlgorithms);
12,212✔
376
    // Indicate that all test are necessary
377
    CryptInitializeToTest();
12,212✔
378
    // Do any library initializations that are necessary. If any fails,
379
    // the caller should go into failure mode;
380
    ok = SupportLibInit();
12,212✔
381
    ok = ok && CryptSymInit();
12,212✔
382
    ok = ok && CryptRandInit();
12,212✔
383
    ok = ok && CryptHashInit();
12,212✔
384
#if ALG_RSA
385
    ok = ok && CryptRsaInit();
12,212✔
386
#endif // TPM_ALG_RSA
387
#if ALG_ECC
388
    ok = ok && CryptEccInit();
12,212✔
389
#endif // TPM_ALG_ECC
390
    return ok;
12,212✔
391
}
392
/* 10.2.6.5.2 CryptStartup() */
393
/* This function is called by TPM2_Startup() to initialize the functions in this cryptographic
394
   library and in the provided CryptoLibrary(). This function and CryptUtilInit() are both provided
395
   so that the implementation may move the initialization around to get the best interaction. */
396
/* Return Values Meaning */
397
/* TRUE startup succeeded */
398
/* FALSE startup failed and caller should place the TPM into Failure Mode */
399
BOOL
400
CryptStartup(
8,177✔
401
             STARTUP_TYPE     type           // IN: the startup type
402
             )
403
{
404
    BOOL            OK;
8,177✔
405
    NOT_REFERENCED(type);
8,177✔
406
    OK = CryptSymStartup();
8,177✔
407
    OK = OK && CryptRandStartup();
8,177✔
408
    OK = OK && CryptHashStartup();
8,177✔
409
#if ALG_RSA
410
    OK = OK && CryptRsaStartup();
8,177✔
411
#endif // TPM_ALG_RSA
412
#if ALG_ECC
413
    OK = OK && CryptEccStartup();
8,177✔
414
#endif // TPM_ALG_ECC
415
         ;
8,177✔
416
#if ALG_ECC
417
    // Don't directly check for SU_RESET because that is the default
418
    if(OK && (type != SU_RESTART) && (type != SU_RESUME))
8,177✔
419
        {
420
            // If the shutdown was orderly, then the values recovered from NV will
421
            // be OK to use.
422
            // Get a new  random commit nonce
423
            gr.commitNonce.t.size = sizeof(gr.commitNonce.t.buffer);
8,145✔
424
            CryptRandomGenerate(gr.commitNonce.t.size, gr.commitNonce.t.buffer);
8,145✔
425
            // Reset the counter and commit array
426
            gr.commitCounter = 0;
8,145✔
427
            MemorySet(gr.commitArray, 0, sizeof(gr.commitArray));
8,145✔
428
        }
429
#endif // TPM_ALG_ECC
430
    return OK;
8,177✔
431
}
432
/* 10.2.6.6 Algorithm-Independent Functions */
433
/* 10.2.6.6.1 Introduction */
434
/* These functions are used generically when a function of a general type (e.g., symmetric
435
   encryption) is required.  The functions will modify the parameters as required to interface to
436
   the indicated algorithms. */
437
/* 10.2.6.6.2 CryptIsAsymAlgorithm() */
438
/* This function indicates if an algorithm is an asymmetric algorithm. */
439
/* Return Values Meaning */
440
/* TRUE if it is an asymmetric algorithm */
441
/* FALSE if it is not an asymmetric algorithm */
442
BOOL
443
CryptIsAsymAlgorithm(
645✔
444
                     TPM_ALG_ID       algID          // IN: algorithm ID
445
                     )
446
{
447
    switch(algID)
645✔
448
        {
449
#if ALG_RSA
450
          case TPM_ALG_RSA:
451
#endif
452
#if ALG_ECC
453
          case TPM_ALG_ECC:
454
#endif
455
            return TRUE;
456
            break;
32✔
457
          default:
458
            break;
32✔
459
        }
460
    return FALSE;
32✔
461
}
462
/* 10.2.6.6.3 CryptSecretEncrypt() */
463
/* This function creates a secret value and its associated secret structure using an asymmetric
464
   algorithm. */
465
/* This function is used by TPM2_Rewrap() TPM2_MakeCredential(), and TPM2_Duplicate(). */
466
/* Error Returns Meaning */
467
/* TPM_RC_ATTRIBUTES keyHandle does not reference a valid decryption key */
468
/* TPM_RC_KEY invalid ECC key (public point is not on the curve) */
469
/* TPM_RC_SCHEME RSA key with an unsupported padding scheme */
470
/* TPM_RC_VALUE numeric value of the data to be decrypted is greater than the RSA key modulus */
471
TPM_RC
472
CryptSecretEncrypt(
35✔
473
                   OBJECT                  *encryptKey,    // IN: encryption key object
474
                   const TPM2B             *label,         // IN: a null-terminated string as L
475
                   TPM2B_DATA              *data,          // OUT: secret value
476
                   TPM2B_ENCRYPTED_SECRET  *secret         // OUT: secret structure
477
                   )
478
{
479
    TPMT_RSA_DECRYPT         scheme;
35✔
480
    TPM_RC                   result = TPM_RC_SUCCESS;
35✔
481
    //
482
    if(data == NULL || secret == NULL)
35✔
483
        return TPM_RC_FAILURE;
484
    // The output secret value has the size of the digest produced by the nameAlg.
485
    data->t.size = CryptHashGetDigestSize(encryptKey->publicArea.nameAlg);
35✔
486
    // The encryption scheme is OAEP using the nameAlg of the encrypt key.
487
    scheme.scheme = TPM_ALG_OAEP;
35✔
488
    scheme.details.anySig.hashAlg = encryptKey->publicArea.nameAlg;
35✔
489
    if(!IS_ATTRIBUTE(encryptKey->publicArea.objectAttributes, TPMA_OBJECT, decrypt))
35✔
490
        return TPM_RC_ATTRIBUTES;
491
    switch(encryptKey->publicArea.type)
35✔
492
        {
493
#if ALG_RSA
494
          case TPM_ALG_RSA:
16✔
495
              {
496
                  // Create secret data from RNG
497
                  CryptRandomGenerate(data->t.size, data->t.buffer);
16✔
498
                  // Encrypt the data by RSA OAEP into encrypted secret
499
                  result = CryptRsaEncrypt((TPM2B_PUBLIC_KEY_RSA *)secret, &data->b,
16✔
500
                                           encryptKey, &scheme, label, NULL);
501
              }
502
              break;
16✔
503
#endif //TPM_ALG_RSA
504
#if ALG_ECC
505
          case TPM_ALG_ECC:
19✔
506
              {
507
                  TPMS_ECC_POINT      eccPublic;
19✔
508
                  TPM2B_ECC_PARAMETER eccPrivate;
19✔
509
                  TPMS_ECC_POINT      eccSecret;
19✔
510
                  BYTE                *buffer = secret->t.secret;
19✔
511
                  // Need to make sure that the public point of the key is on the
512
                  // curve defined by the key.
513
                  if(!CryptEccIsPointOnCurve(
19✔
514
                                             encryptKey->publicArea.parameters.eccDetail.curveID,
19✔
515
                                             &encryptKey->publicArea.unique.ecc))
516
                      result = TPM_RC_KEY;
517
                  else
518
                      {
519
                          // Call crypto engine to create an auxiliary ECC key
520
                          // We assume crypt engine initialization should always success.
521
                          // Otherwise, TPM should go to failure mode.
522
                          CryptEccNewKeyPair(&eccPublic, &eccPrivate,
19✔
523
                                             encryptKey->publicArea.parameters.eccDetail.curveID);
19✔
524
                          // Marshal ECC public to secret structure. This will be used by the
525
                          // recipient to decrypt the secret with their private key.
526
                          secret->t.size = TPMS_ECC_POINT_Marshal(&eccPublic, &buffer, NULL);
19✔
527
                          // Compute ECDH shared secret which is R = [d]Q where d is the
528
                          // private part of the ephemeral key and Q is the public part of a
529
                          // TPM key. TPM_RC_KEY error return from CryptComputeECDHSecret
530
                          // because the auxiliary ECC key is just created according to the
531
                          // parameters of input ECC encrypt key.
532
                          if(CryptEccPointMultiply(&eccSecret,
19✔
533
                                                   encryptKey->publicArea.parameters.eccDetail.curveID,
19✔
534
                                                   &encryptKey->publicArea.unique.ecc, &eccPrivate,
535
                                                   NULL, NULL) != TPM_RC_SUCCESS)
536
                              result = TPM_RC_KEY;
537
                          else
538
                              {
539
                                  // The secret value is computed from Z using KDFe as:
540
                                  // secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
541
                                  // Where:
542
                                  //  HashID  the nameAlg of the decrypt key
543
                                  //  Z   the x coordinate (Px) of the product (P) of the point
544
                                  //      (Q) of the secret and the private x coordinate (de,V)
545
                                  //      of the decryption key
546
                                  //  Use a null-terminated string containing "SECRET"
547
                                  //  PartyUInfo  the x coordinate of the point in the secret
548
                                  //              (Qe,U )
549
                                  //  PartyVInfo  the x coordinate of the public key (Qs,V )
550
                                  //  bits    the number of bits in the digest of HashID
551
                                  // Retrieve seed from KDFe
552
                                  CryptKDFe(encryptKey->publicArea.nameAlg, &eccSecret.x.b,
19✔
553
                                            label, &eccPublic.x.b,
554
                                            &encryptKey->publicArea.unique.ecc.x.b,
555
                                            data->t.size * 8, data->t.buffer);
19✔
556
                              }
557
                      }
558
              }
559
              break;
19✔
560
#endif //TPM_ALG_ECC
561
          default:
×
562
            FAIL(FATAL_ERROR_INTERNAL);
×
563
            break;
564
        }
565
    return result;
566
}
567
/* 10.2.6.6.4 CryptSecretDecrypt() */
568
/* Decrypt a secret value by asymmetric (or symmetric) algorithm This function is used for
569
   ActivateCredential() and Import for asymmetric decryption, and StartAuthSession() for both
570
   asymmetric and symmetric decryption process */
571
/* Error Returns Meaning */
572
/* TPM_RC_ATTRIBUTES RSA key is not a decryption key */
573
/* TPM_RC_BINDING Invalid RSA key (public and private parts are not cryptographically bound. */
574
/* TPM_RC_ECC_POINT ECC point in the secret is not on the curve */
575
/* TPM_RC_INSUFFICIENT failed to retrieve ECC point from the secret */
576
/* TPM_RC_NO_RESULT multiplication resulted in ECC point at infinity */
577
/* TPM_RC_SIZE data to decrypt is not of the same size as RSA key */
578
/* TPM_RC_VALUE For RSA key, numeric value of the encrypted data is greater than the modulus, or the
579
   recovered data is larger than the output buffer. For keyedHash or symmetric key, the secret is
580
   larger than the size of the digest produced by the name algorithm. */
581
/* TPM_RC_FAILURE internal error */
582
TPM_RC
583
CryptSecretDecrypt(
81✔
584
                   OBJECT                 *decryptKey,    // IN: decrypt key
585
                   TPM2B_NONCE             *nonceCaller,   // IN: nonceCaller.  It is needed for
586
                   //     symmetric decryption.  For
587
                   //     asymmetric decryption, this
588
                   //     parameter is NULL
589
                   const TPM2B             *label,         // IN: a value for L
590
                   TPM2B_ENCRYPTED_SECRET  *secret,        // IN: input secret
591
                   TPM2B_DATA              *data           // OUT: decrypted secret value
592
                   )
593
{
594
    TPM_RC      result = TPM_RC_SUCCESS;
81✔
595
    // Decryption for secret
596
    switch(decryptKey->publicArea.type)
81✔
597
        {
598
#if ALG_RSA
599
          case TPM_ALG_RSA:
50✔
600
              {
601
                  TPMT_RSA_DECRYPT        scheme;
50✔
602
                  TPMT_RSA_SCHEME         *keyScheme
50✔
603
                      = &decryptKey->publicArea.parameters.rsaDetail.scheme;
604
                  UINT16                   digestSize;
50✔
605
                  scheme = *(TPMT_RSA_DECRYPT *)keyScheme;
50✔
606
                  // If the key scheme is TPM_ALG_NULL, set the scheme to OAEP and
607
                  // set the algorithm to the name algorithm.
608
                  if(scheme.scheme == TPM_ALG_NULL)
50✔
609
                      {
610
                          // Use OAEP scheme
611
                          scheme.scheme = TPM_ALG_OAEP;
38✔
612
                          scheme.details.oaep.hashAlg = decryptKey->publicArea.nameAlg;
38✔
613
                      }
614
                  // use the digestSize as an indicator of whether or not the scheme
615
                  // is using a supported hash algorithm.
616
                  // Note: depending on the scheme used for encryption, a hashAlg might
617
                  // not be needed. However, the return value has to have some upper
618
                  // limit on the size. In this case, it is the size of the digest of the
619
                  // hash algorithm. It is checked after the decryption is done but, there
620
                  // is no point in doing the decryption if the size is going to be
621
                  // 'wrong' anyway.
622
                  digestSize = CryptHashGetDigestSize(scheme.details.oaep.hashAlg);
50✔
623
                  if(scheme.scheme != TPM_ALG_OAEP || digestSize == 0)
50✔
624
                      return TPM_RC_SCHEME;
×
625
                  // Set the output buffer capacity
626
                  data->t.size = sizeof(data->t.buffer);
50✔
627
                  // Decrypt seed by RSA OAEP
628
                  result = CryptRsaDecrypt(&data->b, &secret->b,
50✔
629
                                           decryptKey, &scheme, label);
630
                  if((result == TPM_RC_SUCCESS) && (data->t.size > digestSize))
50✔
631
                      result = TPM_RC_VALUE;
×
632
              }
633
              break;
50✔
634
#endif //TPM_ALG_RSA
635
#if ALG_ECC
636
          case TPM_ALG_ECC:
31✔
637
              {
638
                  TPMS_ECC_POINT       eccPublic;
31✔
639
                  TPMS_ECC_POINT       eccSecret;
31✔
640
                  BYTE                *buffer = secret->t.secret;
31✔
641
                  INT32                size = secret->t.size;
31✔
642
                  // Retrieve ECC point from secret buffer
643
                  result = TPMS_ECC_POINT_Unmarshal(&eccPublic, &buffer, &size);
31✔
644
                  if(result == TPM_RC_SUCCESS)
31✔
645
                      {
646
                          result = CryptEccPointMultiply(&eccSecret,
62✔
647
                                                         decryptKey->publicArea.parameters.eccDetail.curveID,
31✔
648
                                                         &eccPublic, &decryptKey->sensitive.sensitive.ecc,
649
                                                         NULL, NULL);
650
                          if(result == TPM_RC_SUCCESS)
31✔
651
                              {
652
                                  // Set the size of the "recovered" secret value to be the size
653
                                  // of the digest produced by the nameAlg.
654
                                  data->t.size =
62✔
655
                                      CryptHashGetDigestSize(decryptKey->publicArea.nameAlg);
31✔
656
                                  // The secret value is computed from Z using KDFe as:
657
                                  // secret := KDFe(HashID, Z, Use, PartyUInfo, PartyVInfo, bits)
658
                                  // Where:
659
                                  //  HashID -- the nameAlg of the decrypt key
660
                                  //  Z --  the x coordinate (Px) of the product (P) of the point
661
                                  //        (Q) of the secret and the private x coordinate (de,V)
662
                                  //        of the decryption key
663
                                  //  Use -- a null-terminated string containing "SECRET"
664
                                  //  PartyUInfo -- the x coordinate of the point in the secret
665
                                  //              (Qe,U )
666
                                  //  PartyVInfo -- the x coordinate of the public key (Qs,V )
667
                                  //  bits -- the number of bits in the digest of HashID
668
                                  // Retrieve seed from KDFe
669
                                  CryptKDFe(decryptKey->publicArea.nameAlg, &eccSecret.x.b, label,
31✔
670
                                            &eccPublic.x.b,
671
                                            &decryptKey->publicArea.unique.ecc.x.b,
672
                                            data->t.size * 8, data->t.buffer);
31✔
673
                              }
674
                      }
675
              }
676
              break;
31✔
677
#endif //TPM_ALG_ECC
678
#if !ALG_KEYEDHASH
679
#   error   "KEYEDHASH support is required"
680
#endif
681
          case TPM_ALG_KEYEDHASH:
×
682
            // The seed size can not be bigger than the digest size of nameAlg
683
            if(secret->t.size >
×
684
               CryptHashGetDigestSize(decryptKey->publicArea.nameAlg))
×
685
                result = TPM_RC_VALUE;
686
            else
687
                {
688
                    // Retrieve seed by XOR Obfuscation:
689
                    //    seed = XOR(secret, hash, key, nonceCaller, nullNonce)
690
                    //    where:
691
                    //    secret  the secret parameter from the TPM2_StartAuthHMAC
692
                    //            command that contains the seed value
693
                    //    hash    nameAlg  of tpmKey
694
                    //    key     the key or data value in the object referenced by
695
                    //            entityHandle in the TPM2_StartAuthHMAC command
696
                    //    nonceCaller the parameter from the TPM2_StartAuthHMAC command
697
                    //    nullNonce   a zero-length nonce
698
                    // XOR Obfuscation in place
699
                    CryptXORObfuscation(decryptKey->publicArea.nameAlg,
×
700
                                        &decryptKey->sensitive.sensitive.bits.b,
701
                                        &nonceCaller->b, NULL,
702
                                        secret->t.size, secret->t.secret);
×
703
                    // Copy decrypted seed
704
                    MemoryCopy2B(&data->b, &secret->b, sizeof(data->t.buffer));
×
705
                }
706
            break;
707
          case TPM_ALG_SYMCIPHER:
×
708
              {
709
                  TPM2B_IV                iv = {{0}};
×
710
                  TPMT_SYM_DEF_OBJECT     *symDef;
×
711
                  // The seed size can not be bigger than the digest size of nameAlg
712
                  if(secret->t.size >
×
713
                     CryptHashGetDigestSize(decryptKey->publicArea.nameAlg))
×
714
                      result = TPM_RC_VALUE;
715
                  else
716
                      {
717
                          symDef = &decryptKey->publicArea.parameters.symDetail.sym;
×
718
                          iv.t.size = CryptGetSymmetricBlockSize(symDef->algorithm,
×
719
                                                                 symDef->keyBits.sym);
×
720
                          if(iv.t.size == 0)
×
721
                              return TPM_RC_FAILURE;
×
722
                          if(nonceCaller->t.size >= iv.t.size)
×
723
                              {
724
                                  MemoryCopy(iv.t.buffer, nonceCaller->t.buffer, iv.t.size);
×
725
                              }
726
                          else
727
                              {
728
                                  if(nonceCaller->t.size > sizeof(iv.t.buffer))
×
729
                                      return TPM_RC_FAILURE;
730
                                  MemoryCopy(iv.t.buffer, nonceCaller->t.buffer,  // libtpms changed: use iv.t.buffer
×
731
                                             nonceCaller->t.size);
732
                              }
733
                          // make sure secret will fit
734
                          if(secret->t.size > sizeof(data->t.buffer))
×
735
                              return TPM_RC_FAILURE;
736
                          data->t.size = secret->t.size;
×
737
                          // CFB decrypt, using nonceCaller as iv
738
                          CryptSymmetricDecrypt(data->t.buffer, symDef->algorithm,
×
739
                                                symDef->keyBits.sym,
×
740
                                                decryptKey->sensitive.sensitive.sym.t.buffer,
×
741
                                                &iv, TPM_ALG_CFB, secret->t.size,
742
                                                secret->t.secret);
×
743
                      }
744
              }
745
              break;
×
746
          default:
×
747
            FAIL(FATAL_ERROR_INTERNAL);
×
748
            break;
749
        }
750
    return result;
751
}
752
/* 10.2.6.6.5 CryptParameterEncryption() */
753
/* This function does in-place encryption of a response parameter. */
754
void
755
CryptParameterEncryption(
149✔
756
                         TPM_HANDLE       handle,            // IN: encrypt session handle
757
                         TPM2B           *nonceCaller,       // IN: nonce caller
758
                         INT32            bufferSize,             // IN: size of parameter buffer
759
                         UINT16           leadingSizeInByte, // IN: the size of the leading size field in
760
                         //     bytes
761
                         TPM2B_AUTH      *extraKey,          // IN: additional key material other than
762
                         //     sessionAuth
763
                         BYTE            *buffer             // IN/OUT: parameter buffer to be encrypted
764
                         )
765
{
766
    SESSION     *session = SessionGet(handle);  // encrypt session
149✔
767
    TPM2B_TYPE(TEMP_KEY, (sizeof(extraKey->t.buffer)
149✔
768
                          + sizeof(session->sessionKey.t.buffer)));
769
    TPM2B_TEMP_KEY        key;               // encryption key
149✔
770
    UINT16                cipherSize = 0;    // size of cipher text
149✔
771

772
    if(bufferSize < leadingSizeInByte)
149✔
773
        {
774
            FAIL(FATAL_ERROR_INTERNAL);
×
775
            return;
776
        }
777
    // Parameter encryption for a non-2B is not supported.
778
    if(leadingSizeInByte != 2)
149✔
779
        {
780
            FAIL(FATAL_ERROR_INTERNAL);
×
781
            return;
782
        }
783
    // Retrieve encrypted data size.
784
    if(UINT16_Unmarshal(&cipherSize, &buffer, &bufferSize) != TPM_RC_SUCCESS)
149✔
785
        {
786
            FAIL(FATAL_ERROR_INTERNAL);
×
787
            return;
788
        }
789
    if(cipherSize > bufferSize)
149✔
790
        {
791
            FAIL(FATAL_ERROR_INTERNAL);
×
792
            return;
793
        }
794
    // Compute encryption key by concatenating sessionKey with extra key
795
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
149✔
796
    MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer));
149✔
797
    if(session->symmetric.algorithm == TPM_ALG_XOR)
149✔
798
        // XOR parameter encryption formulation:
799
        //    XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder)
800
        CryptXORObfuscation(session->authHashAlg,
88✔
801
                            &(key.b),
802
                            &(session->nonceTPM.b),
803
                            nonceCaller,
804
                            (UINT32)cipherSize,
805
                            buffer);
806
    else
807
        ParmEncryptSym(session->symmetric.algorithm,
61✔
808
                       session->authHashAlg,
61✔
809
                       session->symmetric.keyBits.aes,
61✔
810
                       &(key.b),
811
                       nonceCaller,
812
                       &(session->nonceTPM.b),
813
                       (UINT32)cipherSize,
814
                       buffer);
815
    return;
149✔
816
}
817
/* 10.2.6.6.6 CryptParameterDecryption() */
818
/* This function does in-place decryption of a command parameter. */
819
/* Error Returns Meaning */
820
/* TPM_RC_SIZE The number of bytes in the input buffer is less than the number of bytes to be
821
   decrypted. */
822
TPM_RC
823
CryptParameterDecryption(
154✔
824
                         TPM_HANDLE       handle,            // IN: encrypted session handle
825
                         TPM2B           *nonceCaller,       // IN: nonce caller
826
                         INT32            bufferSize,        // IN: size of parameter buffer
827
                         UINT16           leadingSizeInByte, // IN: the size of the leading size field in
828
                         //     byte
829
                         TPM2B_AUTH      *extraKey,          // IN: the authValue
830
                         BYTE            *buffer             // IN/OUT: parameter buffer to be decrypted
831
                         )
832
{
833
    SESSION         *session = SessionGet(handle);  // encrypt session
154✔
834
    // The HMAC key is going to be the concatenation of the session key and any
835
    // additional key material (like the authValue). The size of both of these
836
    // is the size of the buffer which can contain a TPMT_HA.
837
    TPM2B_TYPE(HMAC_KEY, (sizeof(extraKey->t.buffer)
154✔
838
                          + sizeof(session->sessionKey.t.buffer)));
839
    TPM2B_HMAC_KEY          key;            // decryption key
154✔
840
    UINT16                  cipherSize = 0; // size of cipher text
154✔
841

842
    if(bufferSize < leadingSizeInByte)
154✔
843
        {
844
            return TPM_RC_INSUFFICIENT;
845
        }
846
    // Parameter encryption for a non-2B is not supported.
847
    if(leadingSizeInByte != 2)
153✔
848
        {
849
            FAIL(FATAL_ERROR_INTERNAL);
×
850
            return TPM_RC_FAILURE;
851
        }
852
    // Retrieve encrypted data size.
853
    if(UINT16_Unmarshal(&cipherSize, &buffer, &bufferSize) != TPM_RC_SUCCESS)
153✔
854
        {
855
            return TPM_RC_INSUFFICIENT;
856
        }
857
    if(cipherSize > bufferSize)
153✔
858
        {
859
        return TPM_RC_SIZE;
860
        }
861
    // Compute decryption key by concatenating sessionAuth with extra input key
862
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
152✔
863
    MemoryConcat2B(&key.b, &extraKey->b, sizeof(key.t.buffer));
152✔
864
    if(session->symmetric.algorithm == TPM_ALG_XOR)
152✔
865
        // XOR parameter decryption formulation:
866
        //    XOR(parameter, hash, sessionAuth, nonceNewer, nonceOlder)
867
        // Call XOR obfuscation function
868
        CryptXORObfuscation(session->authHashAlg,
91✔
869
                            &key.b,
870
                            nonceCaller,
871
                            &(session->nonceTPM.b),
872
                            (UINT32)cipherSize,
873
                            buffer);
874
    else
875
        // Assume that it is one of the symmetric block ciphers.
876
        ParmDecryptSym(session->symmetric.algorithm,
61✔
877
                       session->authHashAlg,
61✔
878
                       session->symmetric.keyBits.sym,
61✔
879
                       &key.b,
880
                       nonceCaller,
881
                       &session->nonceTPM.b,
882
                       (UINT32)cipherSize,
883
                       buffer);
884
    return TPM_RC_SUCCESS;
885
}
886
/* 10.2.6.6.7 CryptComputeSymmetricUnique() */
887
/* This function computes the unique field in public area for symmetric objects. */
888
void
889
CryptComputeSymmetricUnique(
105✔
890
                            TPMT_PUBLIC     *publicArea,    // IN: the object's public area
891
                            TPMT_SENSITIVE  *sensitive,     // IN: the associated sensitive area
892
                            TPM2B_DIGEST    *unique         // OUT: unique buffer
893
                            )
894
{
895
    // For parents (symmetric and derivation), use an HMAC to compute
896
    // the 'unique' field
897
    if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
105✔
898
       && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt))
105✔
899
        {
900
            // Unique field is HMAC(sensitive->seedValue, sensitive->sensitive)
901
            HMAC_STATE      hmacState;
3✔
902
            unique->b.size = CryptHmacStart2B(&hmacState, publicArea->nameAlg,
6✔
903
                                              &sensitive->seedValue.b);
3✔
904
            CryptDigestUpdate2B(&hmacState.hashState,
3✔
905
                                &sensitive->sensitive.any.b);
3✔
906
            CryptHmacEnd2B(&hmacState, &unique->b);
3✔
907
        }
908
    else
909
        {
910
            HASH_STATE  hashState;
102✔
911
            // Unique := Hash(sensitive->seedValue || sensitive->sensitive)
912
            unique->t.size = CryptHashStart(&hashState, publicArea->nameAlg);
102✔
913
            CryptDigestUpdate2B(&hashState, &sensitive->seedValue.b);
102✔
914
            CryptDigestUpdate2B(&hashState, &sensitive->sensitive.any.b);
102✔
915
            CryptHashEnd2B(&hashState, &unique->b);
102✔
916
        }
917
    return;
105✔
918
}
919
/* 10.2.6.6.8 CryptCreateObject() */
920
/* This function creates an object. For an asymmetric key, it will create a key pair and, for a
921
   parent key, a seed value for child protections. */
922
/* For an symmetric object, (TPM_ALG_SYMCIPHER or TPM_ALG_KEYEDHASH), it will create a secret key if
923
   the caller did not provide one. It will create a random secret seed value that is hashed with the
924
   secret value to create the public unique value. */
925
/* publicArea, sensitive, and sensitiveCreate are the only required parameters and are the only ones
926
   that are used by TPM2_Create(). The other parameters are optional and are used when the generated
927
   Object needs to be deterministic. This is the case for both Primary Objects and Derived
928
   Objects. */
929
/* When a seed value is provided, a RAND_STATE will be populated and used for all operations in the
930
   object generation that require a random number. In the simplest case, TPM2_CreatePrimary() will
931
   use seed, label and context with context being the hash of the template. If the Primary Object is
932
   in the Endorsement hierarchy, it will also populate proof with ehProof. */
933
/* For derived keys, seed will be the secret value from the parent, label and context will be set
934
   according to the parameters of TPM2_CreateLoaded() and hashAlg will be set which causes the RAND_STATE
935
   to be a KDF generator. */
936
/* Error Returns Meaning */
937
/* TPM_RC_KEY a provided key is not an allowed value */
938
/* TPM_RC_KEY_SIZE key size in the public area does not match the size in the sensitive creation
939
   area for a symmetric key */
940
/* TPM_RC_NO_RESULT unable to get random values (only in derivation) */
941
/* TPM_RC_RANGE for an RSA key, the exponent is not supported */
942
/* TPM_RC_SIZE sensitive data size is larger than allowed for the scheme for a keyed hash object */
943
/* TPM_RC_VALUE exponent is not prime or could not find a prime using the provided parameters for an
944
   RSA key; unsupported name algorithm for an ECC key */
945
TPM_RC
946
CryptCreateObject(
906✔
947
                  OBJECT                  *object,            // IN: new object structure pointer
948
                  TPMS_SENSITIVE_CREATE   *sensitiveCreate,   // IN: sensitive creation
949
                  RAND_STATE              *rand               // IN: the random number generator
950
                  //      to use
951
                  )
952
{
953
    TPMT_PUBLIC             *publicArea = &object->publicArea;
906✔
954
    TPMT_SENSITIVE          *sensitive = &object->sensitive;
906✔
955
    TPM_RC                   result = TPM_RC_SUCCESS;
906✔
956
    //
957
    // Set the sensitive type for the object
958
    sensitive->sensitiveType = publicArea->type;
906✔
959
    // For all objects, copy the initial authorization data
960
    sensitive->authValue = sensitiveCreate->userAuth;
906✔
961
    // If the TPM is the source of the data, set the size of the provided data to
962
    // zero so that there's no confusion about what to do.
963
    if(IS_ATTRIBUTE(publicArea->objectAttributes,
906✔
964
                    TPMA_OBJECT, sensitiveDataOrigin))
965
        sensitiveCreate->data.t.size = 0;
877✔
966
    // Generate the key and unique fields for the asymmetric keys and just the
967
    // sensitive value for symmetric object
968
    switch(publicArea->type)
906✔
969
        {
970
#if ALG_RSA
971
            // Create RSA key
972
          case TPM_ALG_RSA:
667✔
973
            // RSA uses full object so that it has a place to put the private
974
            // exponent
975
            result = CryptRsaGenerateKey(object, rand);
667✔
976
            break;
667✔
977
#endif // TPM_ALG_RSA
978
#if ALG_ECC
979
            // Create ECC key
980
          case TPM_ALG_ECC:
147✔
981
            result = CryptEccGenerateKey(publicArea, sensitive, rand);
147✔
982
            break;
147✔
983
#endif // TPM_ALG_ECC
984
          case TPM_ALG_SYMCIPHER:
35✔
985
            result = CryptGenerateKeySymmetric(publicArea, sensitive,
35✔
986
                                               sensitiveCreate, rand);
987
            break;
35✔
988
          case TPM_ALG_KEYEDHASH:
57✔
989
            result = CryptGenerateKeyedHash(publicArea, sensitive,
57✔
990
                                            sensitiveCreate, rand);
991
            break;
57✔
992
          default:
×
993
            FAIL(FATAL_ERROR_INTERNAL);
×
994
            break;
906✔
995
        }
996
    if(result != TPM_RC_SUCCESS)
906✔
997
        return result;
998
    // Create the sensitive seed value
999
    // If this is a primary key in the endorsement hierarchy, stir the DRBG state
1000
    // This implementation uses both shProof and ehProof to make sure that there
1001
    // is no leakage of either.
1002
    if(object->attributes.primary && object->attributes.epsHierarchy)
902✔
1003
        {
1004
            DRBG_AdditionalData((DRBG_STATE *)rand, &gp.shProof.b);
309✔
1005
            DRBG_AdditionalData((DRBG_STATE *)rand, &gp.ehProof.b);
309✔
1006
        }
1007
    // Generate a seedValue that is the size of the digest produced by nameAlg
1008
    sensitive->seedValue.t.size =
1,804✔
1009
        DRBG_Generate(rand, object->sensitive.seedValue.t.buffer,
902✔
1010
                      CryptHashGetDigestSize(publicArea->nameAlg));
902✔
1011
    if(g_inFailureMode)
902✔
1012
        return TPM_RC_FAILURE;
1013
    else if(sensitive->seedValue.t.size == 0)
902✔
1014
        return TPM_RC_NO_RESULT;
1015
    // For symmetric objects, need to compute the unique value for the public area
1016
    if(publicArea->type == TPM_ALG_SYMCIPHER
902✔
1017
       || publicArea->type == TPM_ALG_KEYEDHASH)
902✔
1018
        {
1019
            CryptComputeSymmetricUnique(publicArea, sensitive,
92✔
1020
                                        &publicArea->unique.sym);
1021
        }
1022
    else
1023
        {
1024
            // if this is an asymmetric key and it isn't a parent, then
1025
            // get rid of the seed.
1026
            if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)
810✔
1027
               || !IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted))
810✔
1028
                memset(&sensitive->seedValue, 0,
436✔
1029
                       sizeof(sensitive->seedValue));
1030
        }
1031
    // Compute the name
1032
    PublicMarshalAndComputeName(publicArea, &object->name);
902✔
1033
    return result;
902✔
1034
}
1035
/* 10.2.6.6.9 CryptGetSignHashAlg() */
1036
/* Get the hash algorithm of signature from a TPMT_SIGNATURE structure. It assumes the signature is
1037
   not NULL This is a function for easy access */
1038
TPMI_ALG_HASH
1039
CryptGetSignHashAlg(
14✔
1040
                    TPMT_SIGNATURE  *auth           // IN: signature
1041
                    )
1042
{
1043
    if(auth->sigAlg == TPM_ALG_NULL)
14✔
1044
        FAIL(FATAL_ERROR_INTERNAL);
×
1045
    // Get authHash algorithm based on signing scheme
1046
    switch(auth->sigAlg)
14✔
1047
        {
1048
#if ALG_RSA
1049
            // If RSA is supported, both RSASSA and RSAPSS are required
1050
#   if !defined TPM_ALG_RSASSA || !defined TPM_ALG_RSAPSS
1051
#       error "RSASSA and RSAPSS are required for RSA"
1052
#   endif
1053
          case TPM_ALG_RSASSA:
14✔
1054
            return auth->signature.rsassa.hash;
14✔
1055
          case TPM_ALG_RSAPSS:
×
1056
            return auth->signature.rsapss.hash;
×
1057
#endif //TPM_ALG_RSA
1058
#if ALG_ECC
1059
            // If ECC is defined, ECDSA is mandatory
1060
#   ifndef  TPM_ALG_ECDSA
1061
#       error "ECDSA is required for ECC"
1062
#   endif
1063
          case TPM_ALG_ECDSA:
×
1064
            // SM2 and ECSCHNORR are optional
1065
#   if ALG_SM2
1066
          case TPM_ALG_SM2:
1067
#   endif
1068
#   if ALG_ECSCHNORR
1069
          case TPM_ALG_ECSCHNORR:
1070
#   endif
1071
            //all ECC signatures look the same
1072
            return auth->signature.ecdsa.hash;
×
1073
#   if ALG_ECDAA
1074
            // Don't know how to verify an ECDAA signature
1075
          case TPM_ALG_ECDAA:
1076
            break;
1077
#   endif
1078
#endif //TPM_ALG_ECC
1079
          case TPM_ALG_HMAC:
×
1080
            return auth->signature.hmac.hashAlg;
×
1081
          default:
1082
            break;
1083
        }
1084
    return TPM_ALG_NULL;
1085
}
1086
/* 10.2.6.6.10 CryptIsSplitSign() */
1087
/* This function us used to determine if the signing operation is a split signing operation that
1088
   required a TPM2_Commit(). */
1089
BOOL
1090
CryptIsSplitSign(
×
1091
                 TPM_ALG_ID       scheme         // IN: the algorithm selector
1092
                 )
1093
{
1094
    switch(scheme)
×
1095
        {
1096
#   if ALG_ECDAA
1097
          case TPM_ALG_ECDAA:
1098
            return TRUE;
1099
            break;
×
1100
#   endif   // TPM_ALG_ECDAA
1101
          default:
×
1102
            return FALSE;
×
1103
            break;
×
1104
        }
1105
}
1106
/* 10.2.6.6.11 CryptIsAsymSignScheme() */
1107
/* This function indicates if a scheme algorithm is a sign algorithm. */
1108
BOOL
1109
CryptIsAsymSignScheme(
827✔
1110
                      TPMI_ALG_PUBLIC          publicType,        // IN: Type of the object
1111
                      TPMI_ALG_ASYM_SCHEME     scheme             // IN: the scheme
1112
                      )
1113
{
1114
    BOOL            isSignScheme = TRUE;
827✔
1115
    switch(publicType)
827✔
1116
        {
1117
#if ALG_RSA
1118
          case TPM_ALG_RSA:
395✔
1119
            switch(scheme)
395✔
1120
                {
1121
#   if !defined TPM_ALG_RSASSA  || !defined TPM_ALG_RSAPSS
1122
#       error "RSASSA and PSAPSS required if RSA used."
1123
#   endif
1124
                  case TPM_ALG_RSASSA:
1125
                  case TPM_ALG_RSAPSS:
1126
                    break;
1127
                  default:
297✔
1128
                    isSignScheme = FALSE;
297✔
1129
                    break;
297✔
1130
                }
1131
            break;
1132
#endif //TPM_ALG_RSA
1133
#if ALG_ECC
1134
            // If ECC is implemented ECDSA is required
1135
          case TPM_ALG_ECC:
432✔
1136
            switch(scheme)
432✔
1137
                {
1138
                    // Support for ECDSA is required for ECC
1139
                  case TPM_ALG_ECDSA:
1140
#if ALG_ECDAA // ECDAA is optional
1141
                  case TPM_ALG_ECDAA:
1142
#endif
1143
#if ALG_ECSCHNORR // Schnorr is also optional
1144
                  case TPM_ALG_ECSCHNORR:
1145
#endif
1146
#if ALG_SM2 // SM2 is optional
1147
                  case TPM_ALG_SM2:
1148
#endif
1149
                    break;
1150
                  default:
93✔
1151
                    isSignScheme = FALSE;
93✔
1152
                    break;
93✔
1153
                }
1154
            break;
1155
#endif //TPM_ALG_ECC
1156
          default:
1157
            isSignScheme = FALSE;
1158
            break;
1159
        }
1160
    return isSignScheme;
827✔
1161
}
1162
/* 10.2.6.6.12 CryptIsAsymDecryptScheme() */
1163
/* This function indicate if a scheme algorithm is a decrypt algorithm. */
1164
BOOL
1165
CryptIsAsymDecryptScheme(
138✔
1166
                         TPMI_ALG_PUBLIC          publicType,        // IN: Type of the object
1167
                         TPMI_ALG_ASYM_SCHEME     scheme             // IN: the scheme
1168
                         )
1169
{
1170
    BOOL        isDecryptScheme = TRUE;
138✔
1171
    switch(publicType)
138✔
1172
        {
1173
#if ALG_RSA
1174
          case TPM_ALG_RSA:
134✔
1175
            switch(scheme)
134✔
1176
                {
1177
                  case TPM_ALG_RSAES:
1178
                  case TPM_ALG_OAEP:
1179
                    break;
1180
                  default:
4✔
1181
                    isDecryptScheme = FALSE;
4✔
1182
                    break;
4✔
1183
                }
1184
            break;
1185
#endif //TPM_ALG_RSA
1186
#if ALG_ECC
1187
            // If ECC is implemented ECDH is required
1188
          case TPM_ALG_ECC:
4✔
1189
            switch(scheme)
4✔
1190
                {
1191
#if !ALG_ECDH
1192
#   error "ECDH is required for ECC"
1193
#endif
1194
                  case TPM_ALG_ECDH:
1195
#if ALG_SM2
1196
                  case TPM_ALG_SM2:
1197
#endif
1198
#if ALG_ECMQV
1199
                  case TPM_ALG_ECMQV:
1200
#endif
1201
                    break;
1202
                  default:
×
1203
                    isDecryptScheme = FALSE;
×
1204
                    break;
×
1205
                }
1206
            break;
1207
#endif //TPM_ALG_ECC
1208
          default:
1209
            isDecryptScheme = FALSE;
1210
            break;
1211
        }
1212
    return isDecryptScheme;
138✔
1213
}
1214
/* 10.2.6.6.13 CryptSelectSignScheme() */
1215
/* This function is used by the attestation and signing commands.  It implements the rules for
1216
   selecting the signature scheme to use in signing. This function requires that the signing key
1217
   either be TPM_RH_NULL or be loaded. */
1218
/* If a default scheme is defined in object, the default scheme should be chosen, otherwise, the
1219
   input scheme should be chosen. In the case that both object and input scheme has a non-NULL
1220
   scheme algorithm, if the schemes are compatible, the input scheme will be chosen. */
1221
/* This function should not be called if 'signObject->publicArea.type' == TPM_ALG_SYMCIPHER. */
1222
/* Return Values Meaning */
1223
/* TRUE scheme selected */
1224
/* FALSE both scheme and key's default scheme are empty; or scheme is empty while key's default
1225
   scheme requires explicit input scheme (split signing); or non-empty default key scheme differs
1226
   from scheme */
1227
BOOL
1228
CryptSelectSignScheme(
605✔
1229
                      OBJECT              *signObject,    // IN: signing key
1230
                      TPMT_SIG_SCHEME     *scheme         // IN/OUT: signing scheme
1231
                      )
1232
{
1233
    TPMT_SIG_SCHEME     *objectScheme;
605✔
1234
    TPMT_PUBLIC         *publicArea;
605✔
1235
    BOOL                 OK;
605✔
1236
    // If the signHandle is TPM_RH_NULL, then the NULL scheme is used, regardless
1237
    // of the setting of scheme
1238
    if(signObject == NULL)
605✔
1239
        {
1240
            OK = TRUE;
8✔
1241
            scheme->scheme = TPM_ALG_NULL;
8✔
1242
            scheme->details.any.hashAlg = TPM_ALG_NULL;
8✔
1243
        }
1244
    else
1245
        {
1246
            // assignment to save typing.
1247
            publicArea = &signObject->publicArea;
597✔
1248
            // A symmetric cipher can be used to encrypt and decrypt but it can't
1249
            // be used for signing
1250
            if(publicArea->type == TPM_ALG_SYMCIPHER)
597✔
1251
                return FALSE;
1252
            // Point to the scheme object
1253
            if(CryptIsAsymAlgorithm(publicArea->type))
597✔
1254
                objectScheme =
565✔
1255
                    (TPMT_SIG_SCHEME *)&publicArea->parameters.asymDetail.scheme;
1256
            else
1257
                objectScheme =
32✔
1258
                    (TPMT_SIG_SCHEME *)&publicArea->parameters.keyedHashDetail.scheme;
1259
            // If the object doesn't have a default scheme, then use the
1260
            // input scheme.
1261
            if(objectScheme->scheme == TPM_ALG_NULL)
597✔
1262
                {
1263
                    // Input and default can't both be NULL
1264
                    OK = (scheme->scheme != TPM_ALG_NULL);
472✔
1265
                    // Assume that the scheme is compatible with the key. If not,
1266
                    // an error will be generated in the signing operation.
1267
                }
1268
            else if(scheme->scheme == TPM_ALG_NULL)
125✔
1269
                {
1270
                    // input scheme is NULL so use default
1271
                    // First, check to see if the default requires that the caller
1272
                    // provided scheme data
1273
                    OK = !CryptIsSplitSign(objectScheme->scheme);
×
1274
                    if(OK)
×
1275
                        {
1276
                            // The object has a scheme and the input is TPM_ALG_NULL so copy
1277
                            // the object scheme as the final scheme. It is better to use a
1278
                            // structure copy than a copy of the individual fields.
1279
                            *scheme = *objectScheme;
×
1280
                        }
1281
                }
1282
            else
1283
                {
1284
                    // Both input and object have scheme selectors
1285
                    // If the scheme and the hash are not the same then...
1286
                    // NOTE: the reason that there is no copy here is that the input
1287
                    // might contain extra data for a split signing scheme and that
1288
                    // data is not in the object so, it has to be preserved.
1289
                    OK = (objectScheme->scheme == scheme->scheme)
125✔
1290
                         && (objectScheme->details.any.hashAlg
125✔
1291
                             == scheme->details.any.hashAlg);
125✔
1292
                }
1293
        }
1294
    return OK;
1295
}
1296
/* 10.2.6.6.14 CryptSign() */
1297
/* Sign a digest with asymmetric key or HMAC. This function is called by attestation commands and
1298
   the generic TPM2_Sign() command. This function checks the key scheme and digest size.  It does
1299
   not check if the sign operation is allowed for restricted key.  It should be checked before the
1300
   function is called. The function will assert if the key is not a signing key. */
1301
/* Error Returns Meaning */
1302
/* TPM_RC_SCHEME signScheme is not compatible with the signing key type */
1303
/* TPM_RC_VALUE digest value is greater than the modulus of signHandle or size of hashData does not
1304
   match hash algorithm insignScheme (for an RSA key); invalid commit status or failed to generate r
1305
   value (for an ECC key) */
1306
TPM_RC
1307
CryptSign(
588✔
1308
          OBJECT              *signKey,       // IN: signing key
1309
          TPMT_SIG_SCHEME     *signScheme,    // IN: sign scheme.
1310
          TPM2B_DIGEST        *digest,        // IN: The digest being signed
1311
          TPMT_SIGNATURE      *signature      // OUT: signature
1312
          )
1313
{
1314
    TPM_RC               result = TPM_RC_SCHEME;
588✔
1315
    // Initialize signature scheme
1316
    signature->sigAlg = signScheme->scheme;
588✔
1317
    // If the signature algorithm is TPM_ALG_NULL or the signing key is NULL,
1318
    // then we are done
1319
    if((signature->sigAlg == TPM_ALG_NULL) || (signKey == NULL))
588✔
1320
        return TPM_RC_SUCCESS;
1321
    // Initialize signature hash
1322
    // Note: need to do the check for TPM_ALG_NULL first because the null scheme
1323
    // doesn't have a hashAlg member.
1324
    signature->signature.any.hashAlg = signScheme->details.any.hashAlg;
588✔
1325
    // perform sign operation based on different key type
1326
    switch(signKey->publicArea.type)
588✔
1327
        {
1328
#if ALG_RSA
1329
          case TPM_ALG_RSA:
448✔
1330
            result = CryptRsaSign(signature, signKey, digest, NULL);
448✔
1331
            break;
448✔
1332
#endif //TPM_ALG_RSA
1333
#if ALG_ECC
1334
          case TPM_ALG_ECC:
112✔
1335
            // The reason that signScheme is passed to CryptEccSign but not to the
1336
            // other signing methods is that the signing for ECC may be split and
1337
            // need the 'r' value that is in the scheme but not in the signature.
1338
            result = CryptEccSign(signature, signKey, digest,
112✔
1339
                                  (TPMT_ECC_SCHEME *)signScheme, NULL);
1340
            break;
112✔
1341
#endif //TPM_ALG_ECC
1342
          case TPM_ALG_KEYEDHASH:
28✔
1343
            result = CryptHmacSign(signature, signKey, digest);
28✔
1344
            break;
28✔
1345
          default:
×
1346
            FAIL(FATAL_ERROR_INTERNAL);
×
1347
            break;
1348
        }
1349
    return result;
1350
}
1351
/* 10.2.6.6.15 CryptValidateSignature() */
1352
/* This function is used to verify a signature.  It is called by TPM2_VerifySignature() and
1353
   TPM2_PolicySigned(). */
1354
/* Since this operation only requires use of a public key, no consistency checks are necessary for
1355
   the key to signature type because a caller can load any public key that they like with any scheme
1356
   that they like. This routine simply makes sure that the signature is correct, whatever the
1357
   type. */
1358
/* Error Returns Meaning */
1359
/* TPM_RC_SIGNATURE the signature is not genuine */
1360
/* TPM_RC_SCHEME the scheme is not supported */
1361
/* TPM_RC_HANDLE an HMAC key was selected but the private part of the key is not loaded */
1362
TPM_RC
1363
CryptValidateSignature(
783✔
1364
                       TPMI_DH_OBJECT   keyHandle,     // IN: The handle of sign key
1365
                       TPM2B_DIGEST    *digest,        // IN: The digest being validated
1366
                       TPMT_SIGNATURE  *signature      // IN: signature
1367
                       )
1368
{
1369
    // NOTE: HandleToObject will either return a pointer to a loaded object or
1370
    // will assert. It will never return a non-valid value. This makes it save
1371
    // to initialize 'publicArea' with the return value from HandleToObject()
1372
    // without checking it first.
1373
    OBJECT              *signObject = HandleToObject(keyHandle);
783✔
1374
    TPMT_PUBLIC         *publicArea = &signObject->publicArea;
783✔
1375
    TPM_RC               result = TPM_RC_SCHEME;
783✔
1376
    // The input unmarshaling should prevent any input signature from being
1377
    // a NULL signature, but just in case
1378
    if(signature->sigAlg == TPM_ALG_NULL)
783✔
1379
        return TPM_RC_SIGNATURE;
1380
    switch(publicArea->type)
783✔
1381
        {
1382
#if ALG_RSA
1383
          case TPM_ALG_RSA:
657✔
1384
              {
1385
                  //
1386
                  // Call RSA code to verify signature
1387
                  result = CryptRsaValidateSignature(signature, signObject, digest);
657✔
1388
                  break;
657✔
1389
              }
1390
#endif //TPM_ALG_RSA
1391
#if ALG_ECC
1392
          case TPM_ALG_ECC:
106✔
1393
            result = CryptEccValidateSignature(signature, signObject, digest);
106✔
1394
            break;
106✔
1395
#endif // TPM_ALG_ECC
1396
          case TPM_ALG_KEYEDHASH:
20✔
1397
            if(signObject->attributes.publicOnly)
20✔
1398
                result = TPM_RCS_HANDLE;
1399
            else
1400
                result = CryptHMACVerifySignature(signObject, digest, signature);
20✔
1401
            break;
1402
          default:
1403
            break;
1404
        }
1405
    return result;
1406
}
1407
/* 10.2.6.6.16 CryptGetTestResult */
1408
/* This function returns the results of a self-test function. */
1409
/* NOTE: the behavior in this function is NOT the correct behavior for a real TPM implementation.
1410
   An artificial behavior is placed here due to the limitation of a software simulation environment.
1411
   For the correct behavior, consult the part 3 specification for TPM2_GetTestResult(). */
1412
TPM_RC
1413
CryptGetTestResult(
5✔
1414
                   TPM2B_MAX_BUFFER    *outData        // OUT: test result data
1415
                   )
1416
{
1417
    outData->t.size = 0;
5✔
1418
    return TPM_RC_SUCCESS;
5✔
1419
}
1420
/* 10.2.6.6.17 CryptValidateKeys() */
1421
/* This function is used to verify that the key material of an object is valid. For a publicOnly
1422
   object, the key is verified for size and, if it is an ECC key, it is verified to be on the
1423
   specified curve. For a key with a sensitive area, the binding between the public and private
1424
   parts of the key are verified. If the nameAlg of the key is TPM_ALG_NULL, then the size of the
1425
   sensitive area is verified but the public portion is not verified, unless the key is an RSA
1426
   key. For an RSA key, the reason for loading the sensitive area is to use it. The only way to use
1427
   a private RSA key is to compute the private exponent. To compute the private exponent, the public
1428
   modulus is used. */
1429
/* Error Returns Meaning */
1430
/* TPM_RC_BINDING the public and private parts are not cryptographically bound */
1431
/* TPM_RC_HASH cannot have a publicOnly key with nameAlg of TPM_ALG_NULL */
1432
/* TPM_RC_KEY the public unique is not valid */
1433
/* TPM_RC_KEY_SIZE the private area key is not valid */
1434
/* TPM_RC_TYPE the types of the sensitive and private parts do not match */
1435
TPM_RC
1436
CryptValidateKeys(
574✔
1437
                  TPMT_PUBLIC      *publicArea,
1438
                  TPMT_SENSITIVE   *sensitive,
1439
                  TPM_RC            blamePublic,
1440
                  TPM_RC            blameSensitive
1441
                  )
1442
{
1443
    TPM_RC               result;
574✔
1444
    UINT16               keySizeInBytes;
574✔
1445
    UINT16               digestSize = CryptHashGetDigestSize(publicArea->nameAlg);
574✔
1446
    TPMU_PUBLIC_PARMS   *params = &publicArea->parameters;
574✔
1447
    TPMU_PUBLIC_ID      *unique = &publicArea->unique;
574✔
1448
    if(sensitive != NULL)
574✔
1449
        {
1450
            // Make sure that the types of the public and sensitive are compatible
1451
            if(publicArea->type != sensitive->sensitiveType)
453✔
1452
                return TPM_RCS_TYPE + blameSensitive;
4✔
1453
            // Make sure that the authValue is not bigger than allowed
1454
            // If there is no name algorithm, then the size just needs to be less than
1455
            // the maximum size of the buffer used for authorization. That size check
1456
            // was made during unmarshaling of the sensitive area
1457
            if((sensitive->authValue.t.size) > digestSize && (digestSize > 0))
449✔
1458
                return TPM_RCS_SIZE + blameSensitive;
×
1459
        }
1460
    switch(publicArea->type)
570✔
1461
        {
1462
#if ALG_RSA
1463
          case TPM_ALG_RSA:
218✔
1464
            keySizeInBytes = BITS_TO_BYTES(params->rsaDetail.keyBits);
218✔
1465
            // Regardless of whether there is a sensitive area, the public modulus
1466
            // needs to have the correct size. Otherwise, it can't be used for
1467
            // any public key operation nor can it be used to compute the private
1468
            // exponent.
1469
            // NOTE: This implementation only supports key sizes that are multiples
1470
            // of 1024 bits which means that the MSb of the 0th byte will always be
1471
            // SET in either a prime or the public modulus.
1472
            if((unique->rsa.t.size != keySizeInBytes)
218✔
1473
               || (unique->rsa.t.buffer[0] < 0x80))
218✔
1474
                return TPM_RCS_KEY + blamePublic;
56✔
1475
            if(params->rsaDetail.exponent != 0
162✔
1476
               && params->rsaDetail.exponent < 7)
162✔
1477
                return TPM_RCS_VALUE + blamePublic;
4✔
1478
            if(sensitive != NULL)
158✔
1479
                {
1480
                    // If there is a sensitive area, it has to be the correct size
1481
                    // including having the correct high order bit SET.
1482
                    if(((sensitive->sensitive.rsa.t.size * 2) != keySizeInBytes)
120✔
1483
                       || (sensitive->sensitive.rsa.t.buffer[0] < 0x80))
120✔
1484
                        return TPM_RCS_KEY_SIZE + blameSensitive;
4✔
1485
                }
1486
            break;
1487
#endif
1488
#if ALG_ECC
1489
          case TPM_ALG_ECC:
323✔
1490
              {
1491
                  TPMI_ECC_CURVE      curveId;
323✔
1492
                  curveId = params->eccDetail.curveID;
323✔
1493
                  keySizeInBytes = BITS_TO_BYTES(CryptEccGetKeySizeForCurve(curveId));
323✔
1494
                  if(sensitive == NULL)
323✔
1495
                      {
1496
                          // Validate the public key size
1497
                          if(unique->ecc.x.t.size != keySizeInBytes
75✔
1498
                             || unique->ecc.y.t.size != keySizeInBytes)
51✔
1499
                              return TPM_RCS_KEY + blamePublic;
24✔
1500
                          if(publicArea->nameAlg != TPM_ALG_NULL)
51✔
1501
                              {
1502
                                  if(!CryptEccIsPointOnCurve(curveId, &unique->ecc))
51✔
1503
                                      return TPM_RCS_ECC_POINT + blamePublic;
4✔
1504
                              }
1505
                      }
1506
                  else
1507
                      {
1508
                          // If the nameAlg is TPM_ALG_NULL, then only verify that the
1509
                          // private part of the key is OK.
1510
                          if(!CryptEccIsValidPrivateKey(&sensitive->sensitive.ecc,
248✔
1511
                                                        curveId))
1512
                              return TPM_RCS_KEY_SIZE;
1513
                          if(publicArea->nameAlg != TPM_ALG_NULL)
244✔
1514
                              {
1515
                                  // Full key load, verify that the public point belongs to the
1516
                                  // private key.
1517
                                  TPMS_ECC_POINT          toCompare;
244✔
1518
                                  result = CryptEccPointMultiply(&toCompare, curveId, NULL,
244✔
1519
                                                                 &sensitive->sensitive.ecc,
1520
                                                                 NULL, NULL);
1521
                                  if(result != TPM_RC_SUCCESS)
244✔
1522
                                      return TPM_RCS_BINDING;
196✔
1523
                                  else
1524
                                      {
1525
                                          // Make sure that the private key generated the public key.
1526
                                          // The input values and the values produced by the point
1527
                                          // multiply may not be the same size so adjust the computed
1528
                                          // value to match the size of the input value by adding or
1529
                                          // removing zeros.
1530
                                          AdjustNumberB(&toCompare.x.b, unique->ecc.x.t.size);
244✔
1531
                                          AdjustNumberB(&toCompare.y.b, unique->ecc.y.t.size);
244✔
1532
                                          if(!MemoryEqual2B(&unique->ecc.x.b, &toCompare.x.b)
244✔
1533
                                             || !MemoryEqual2B(&unique->ecc.y.b, &toCompare.y.b))
48✔
1534
                                              return TPM_RCS_BINDING;
196✔
1535
                                      }
1536
                              }
1537
                      }
1538
                  break;
1539
              }
1540
#endif
1541
          default:
29✔
1542
            // Checks for SYMCIPHER and KEYEDHASH are largely the same
1543
            // If public area has a nameAlg, then validate the public area size
1544
            // and if there is also a sensitive area, validate the binding
1545
            // For consistency, if the object is public-only just make sure that
1546
            // the unique field is consistent with the name algorithm
1547
            if(sensitive == NULL)
29✔
1548
                {
1549
                    if(unique->sym.t.size != digestSize)
8✔
1550
                        return TPM_RCS_KEY + blamePublic;
8✔
1551
                }
1552
            else
1553
                {
1554
                    // Make sure that the key size in the sensitive area is consistent.
1555
                    if(publicArea->type == TPM_ALG_SYMCIPHER)
21✔
1556
                        {
1557
                            result = CryptSymKeyValidate(&params->symDetail.sym,
8✔
1558
                                                         &sensitive->sensitive.sym);
1559
                            if(result != TPM_RC_SUCCESS)
8✔
1560
                                return result + blameSensitive;
4✔
1561
                        }
1562
                    else
1563
                        {
1564
                            // For a keyed hash object, the key has to be less than the
1565
                            // smaller of the block size of the hash used in the scheme or
1566
                            // 128 bytes. The worst case value is limited by the
1567
                            // unmarshaling code so the only thing left to be checked is
1568
                            // that it does not exceed the block size of the hash.
1569
                            // by the hash algorithm of the scheme.
1570
                            TPMT_KEYEDHASH_SCHEME       *scheme;
13✔
1571
                            UINT16                       maxSize;
13✔
1572
                            scheme = &params->keyedHashDetail.scheme;
13✔
1573
                            if(scheme->scheme == TPM_ALG_XOR)
13✔
1574
                                {
1575
                                    maxSize = CryptHashGetBlockSize(scheme->details.xorr.hashAlg);
×
1576
                                }
1577
                            else if(scheme->scheme == TPM_ALG_HMAC)
13✔
1578
                                {
1579
                                    maxSize = CryptHashGetBlockSize(scheme->details.hmac.hashAlg);
8✔
1580
                                }
1581
                            else if(scheme->scheme == TPM_ALG_NULL)
5✔
1582
                                {
1583
                                    // Not signing or xor so must be a data block
1584
                                    maxSize = 128;
1585
                                }
1586
                            else
1587
                                return TPM_RCS_SCHEME + blamePublic;
×
1588
                            if(sensitive->sensitive.bits.t.size > maxSize)
13✔
1589
                                return TPM_RCS_KEY_SIZE + blameSensitive;
×
1590
                        }
1591
                    // If there is a nameAlg, check the binding
1592
                    if(publicArea->nameAlg != TPM_ALG_NULL)
17✔
1593
                        {
1594
                            TPM2B_DIGEST            compare;
17✔
1595
                            if(sensitive->seedValue.t.size != digestSize)
17✔
1596
                                return TPM_RCS_KEY_SIZE + blameSensitive;
8✔
1597
                            CryptComputeSymmetricUnique(publicArea, sensitive, &compare);
13✔
1598
                            if(!MemoryEqual2B(&unique->sym.b, &compare.b))
13✔
1599
                                return TPM_RC_BINDING;
1600
                        }
1601
                }
1602
            break;
1603
        }
1604
    // For a parent, need to check that the seedValue is the correct size for
1605
    // protections. It should be at least half the size of the nameAlg
1606
    if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
258✔
1607
       && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
258✔
1608
       && sensitive != NULL
29✔
1609
       && publicArea->nameAlg != TPM_ALG_NULL)
1✔
1610
        {
1611
            if((sensitive->seedValue.t.size < (digestSize / 2))
1✔
1612
               || (sensitive->seedValue.t.size > digestSize))
1✔
1613
                return TPM_RCS_SIZE + blameSensitive;
×
1614
        }
1615
    return TPM_RC_SUCCESS;
1616
}
1617
/* 10.2.6.6.18 CryptSelectMac() */
1618
/* This function is used to set the MAC scheme based on the key parameters and the input scheme. */
1619
/* Error Returns Meaning */
1620
/* TPM_RC_SCHEME the scheme is not a valid mac scheme */
1621
/* TPM_RC_TYPE the input key is not a type that supports a mac */
1622
/* TPM_RC_VALUE the input scheme and the key scheme are not compatible */
1623
TPM_RC
1624
CryptSelectMac(
40✔
1625
               TPMT_PUBLIC             *publicArea,
1626
               TPMI_ALG_MAC_SCHEME     *inMac
1627
               )
1628
{
1629
    TPM_ALG_ID              macAlg = TPM_ALG_NULL;
40✔
1630
    switch(publicArea->type)
40✔
1631
        {
1632
          case TPM_ALG_KEYEDHASH:
40✔
1633
              {
1634
                  // Local value to keep lines from getting too long
1635
                  TPMT_KEYEDHASH_SCHEME   *scheme;
40✔
1636
                  scheme = &publicArea->parameters.keyedHashDetail.scheme;
40✔
1637
                  // Expect that the scheme is either HMAC or NULL
1638
                  if(scheme->scheme != TPM_ALG_NULL)
40✔
1639
                      macAlg = scheme->details.hmac.hashAlg;
40✔
1640
                  break;
1641
              }
1642
          case TPM_ALG_SYMCIPHER:
×
1643
              {
1644
                  TPMT_SYM_DEF_OBJECT     *scheme;
×
1645
                  scheme = &publicArea->parameters.symDetail.sym;
×
1646
                  // Expect that the scheme is either valid symmetric cipher or NULL
1647
                  if(scheme->algorithm != TPM_ALG_NULL)
×
1648
                      macAlg = scheme->mode.sym;
×
1649
                  break;
1650
              }
1651
          default:
1652
            return TPM_RCS_TYPE;
1653
        }
1654
    // If the input value is not TPM_ALG_NULL ...
1655
    if(*inMac != TPM_ALG_NULL)
40✔
1656
        {
1657
            // ... then either the scheme in the key must be TPM_ALG_NULL or the input
1658
            // value must match
1659
            if((macAlg != TPM_ALG_NULL) && (*inMac != macAlg))
40✔
1660
                return TPM_RCS_VALUE;
1661
        }
1662
    else
1663
        {
1664
            // Since the input value is TPM_ALG_NULL, then the key value can't be
1665
            // TPM_ALG_NULL
1666
            if(macAlg == TPM_ALG_NULL)
×
1667
                return TPM_RCS_VALUE;
1668
            *inMac = macAlg;
×
1669
        }
1670
    if(!CryptMacIsValidForKey(publicArea->type, *inMac, FALSE))
40✔
1671
        return TPM_RCS_SCHEME;
×
1672
    return TPM_RC_SUCCESS;
1673
}
1674
/* 10.2.6.6.19 CryptMacIsValidForKey() */
1675
/* Check to see if the key type is compatible with the mac type */
1676
BOOL
1677
CryptMacIsValidForKey(
40✔
1678
                      TPM_ALG_ID          keyType,
1679
                      TPM_ALG_ID          macAlg,
1680
                      BOOL                flag
1681
                      )
1682
{
1683
    switch(keyType)
40✔
1684
        {
1685
          case TPM_ALG_KEYEDHASH:
40✔
1686
            return CryptHashIsValidAlg(macAlg, flag);
40✔
1687
            break;
×
1688
          case TPM_ALG_SYMCIPHER:
×
1689
            return CryptSmacIsValidAlg(macAlg, flag);
×
1690
            break;
1691
          default:
1692
            break;
1693
        }
1694
    return FALSE;
1695
}
1696
/* 10.2.6.6.20 CryptSmacIsValidAlg() */
1697
/* This function is used to test if an algorithm is a supported SMAC algorithm. It needs to be
1698
   updated as new algorithms are added. */
1699
BOOL
1700
CryptSmacIsValidAlg(
84✔
1701
                    TPM_ALG_ID      alg,
1702
                    BOOL            FLAG        // IN: Indicates if TPM_ALG_NULL is valid
1703
                    )
1704
{
1705
    switch (alg)
84✔
1706
        {
1707
#if ALG_CMAC
1708
          case TPM_ALG_CMAC:
1709
            return TRUE;
1710
            break;
×
1711
#endif
1712
          case TPM_ALG_NULL:
×
1713
            return FLAG;
×
1714
            break;
×
1715
          default:
×
1716
            return FALSE;
×
1717
        }
1718
}
1719
/* 10.2.6.6.21 CryptSymModeIsValid() */
1720
/* Function checks to see if an algorithm ID is a valid, symmetric block cipher mode for the TPM. If
1721
   flag is SET, them TPM_ALG_NULL is a valid mode. not include the modes used for SMAC */
1722
BOOL
1723
CryptSymModeIsValid(
71✔
1724
                    TPM_ALG_ID          mode,
1725
                    BOOL                flag
1726
                    )
1727
{
1728
    switch(mode)
71✔
1729
        {
1730
#if         ALG_CTR
1731
          case TPM_ALG_CTR:
1732
#endif // ALG_CTR
1733
#if         ALG_OFB
1734
          case TPM_ALG_OFB:
1735
#endif // ALG_OFB
1736
#if         ALG_CBC
1737
          case TPM_ALG_CBC:
1738
#endif // ALG_CBC
1739
#if         ALG_CFB
1740
          case TPM_ALG_CFB:
1741
#endif // ALG_CFB
1742
#if         ALG_ECB
1743
          case TPM_ALG_ECB:
1744
#endif // ALG_ECB
1745
            return TRUE;
1746
          case TPM_ALG_NULL:
×
1747
            return flag;
×
1748
            break;
×
1749
          default:
1750
            break;
×
1751
        }
1752
    return FALSE;
×
1753
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc