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

stefanberger / libtpms / #2015

05 Aug 2025 12:00AM UTC coverage: 77.231% (+0.4%) from 76.783%
#2015

push

travis-ci

web-flow
Merge 3cee57d10 into c0a2f2222

36108 of 46753 relevant lines covered (77.23%)

122677.58 hits per line

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

88.32
/src/tpm2/AlgorithmTests.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                          Code to perform the various self-test functions.        */
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 - 2024                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
//** Introduction
62
// This file contains the code to perform the various self-test functions.
63
//
64
// NOTE: In this implementation, large local variables are made static to minimize
65
// stack usage, which is critical for stack-constrained platforms.
66

67
//** Includes and Defines
68
#include "Tpm.h"
69

70
#define SELF_TEST_DATA
71

72
#if ENABLE_SELF_TESTS
73

74
// These includes pull in the data structures. They contain data definitions for the
75
// various tests.
76
#  include "SelfTest.h"
77
#  include "SymmetricTest.h"
78
#  include "RsaTestData.h"
79
#  include "EccTestData.h"
80
#  include "HashTestData.h"
81
#  include "KdfTestData.h"
82

83
#  define TEST_DEFAULT_TEST_HASH(vector)        \
84
      if(TEST_BIT(DEFAULT_TEST_HASH, g_toTest)) \
85
          TestHash(DEFAULT_TEST_HASH, vector);
86

87
// Make sure that the algorithm has been tested
88
#  define CLEAR_BOTH(alg)               \
89
      {                                 \
90
          CLEAR_BIT(alg, *toTest);      \
91
          if(toTest != &g_toTest)       \
92
              CLEAR_BIT(alg, g_toTest); \
93
      }
94

95
#  define SET_BOTH(alg)               \
96
      {                               \
97
          SET_BIT(alg, *toTest);      \
98
          if(toTest != &g_toTest)     \
99
              SET_BIT(alg, g_toTest); \
100
      }
101

102
#  define TEST_BOTH(alg)                                                         \
103
      ((toTest != &g_toTest) ? TEST_BIT(alg, *toTest) || TEST_BIT(alg, g_toTest) \
104
                             : TEST_BIT(alg, *toTest))
105

106
// Can only cancel if doing a list.
107
#  define CHECK_CANCELED                             \
108
      if(_plat__IsCanceled() && toTest != &g_toTest) \
109
          return TPM_RC_CANCELED;
110

111
//** Hash Tests
112

113
//*** Description
114
// The hash test does a known-value HMAC using the specified hash algorithm.
115

116
//*** TestHash()
117
// The hash test function.
118
static TPM_RC TestHash(TPM_ALG_ID hashAlg, ALGORITHM_VECTOR* toTest)
9,359✔
119
{
120
    static TPM2B_DIGEST computed;  // value computed
9,359✔
121
    static HMAC_STATE   state;
9,359✔
122
    UINT16              digestSize;
9,359✔
123
    const TPM2B*        testDigest = NULL;
9,359✔
124
    //    TPM2B_TYPE(HMAC_BLOCK, DEFAULT_TEST_HASH_BLOCK_SIZE);
125

126
    pAssert(hashAlg != TPM_ALG_NULL);
9,359✔
127
#  define HASH_CASE_FOR_TEST(HASH, hash)     \
128
      case ALG_##HASH##_VALUE:               \
129
          testDigest = &c_##HASH##_digest.b; \
130
          break;
131
    switch(hashAlg)
9,359✔
132
    {
133
        FOR_EACH_HASH(HASH_CASE_FOR_TEST)
1,317✔
134

135
        default:
×
136
            FAIL(FATAL_ERROR_INTERNAL);
×
137
    }
138
    // Clear the to-test bits
139
    CLEAR_BOTH(hashAlg);
9,359✔
140

141
    // If there is an algorithm without test vectors, then assume that things are OK.
142
    if(testDigest == NULL || testDigest->size == 0)
9,359✔
143
        return TPM_RC_SUCCESS;
144

145
    // Set the HMAC key to twice the digest size
146
    digestSize = CryptHashGetDigestSize(hashAlg);
9,359✔
147
    CryptHmacStart(&state, hashAlg, digestSize * 2, (BYTE*)c_hashTestKey.t.buffer);
9,359✔
148
    CryptDigestUpdate(&state.hashState,
18,718✔
149
                      2 * CryptHashGetBlockSize(hashAlg),
9,359✔
150
                      (BYTE*)c_hashTestData.t.buffer);
151
    computed.t.size = digestSize;
9,359✔
152
    CryptHmacEnd(&state, digestSize, computed.t.buffer);
9,359✔
153
    if((testDigest->size != computed.t.size)
9,359✔
154
       || (memcmp(testDigest->buffer, computed.t.buffer, computed.b.size) != 0))
9,359✔
155
        SELF_TEST_FAILURE;
×
156
    return TPM_RC_SUCCESS;
157
}
158
// libtpms added begin
159
#if SMAC_IMPLEMENTED && ALG_CMAC
160
static TPM_RC
161
TestSMAC(
23✔
162
         ALGORITHM_VECTOR    *toTest LIBTPMS_ATTR_UNUSED
163
         )
164
{
165
    HMAC_STATE          state;
23✔
166
    UINT16              copied;
23✔
167
    BYTE                out[MAX_SYM_BLOCK_SIZE];
23✔
168
    UINT32              outSize = sizeof(out);
23✔
169
    UINT16              blocksize;
23✔
170
    int                 i;
23✔
171
    TPMU_PUBLIC_PARMS   cmac_keyParms;
23✔
172

173
    // initializing this statically seems impossible with gcc...
174
    cmac_keyParms.symDetail.sym.algorithm = TPM_ALG_AES;
23✔
175
    cmac_keyParms.symDetail.sym.keyBits.sym = 128;
23✔
176

177
    for (i = 0; CMACTests[i].key; i++ )
115✔
178
        {
179
            blocksize = CryptMacStart(&state, &cmac_keyParms,
92✔
180
                                      TPM_ALG_CMAC, CMACTests[i].key);
181
            pAssert(blocksize <= outSize);
92✔
182
            CryptDigestUpdate(&state.hashState, CMACTests[i].datalen,
92✔
183
                              CMACTests[i].data);
92✔
184
            copied = CryptMacEnd(&state, outSize, out);
92✔
185
            if((CMACTests[i].outlen != copied)
92✔
186
              || (memcmp(out, CMACTests[i].out, CMACTests[i].outlen) != 0)) {
92✔
187
                SELF_TEST_FAILURE;
×
188
            }
189
        }
190
    return TPM_RC_SUCCESS;
23✔
191
}
192
#endif
193
// libtpms added end
194

195
//** Symmetric Test Functions
196

197
//*** MakeIv()
198
// Internal function to make the appropriate IV depending on the mode.
199
static UINT32 MakeIv(TPM_ALG_ID mode,  // IN: symmetric mode
1,088✔
200
                     UINT32     size,  // IN: block size of the algorithm
201
                     BYTE*      iv     // OUT: IV to fill in
202
)
203
{
204
    BYTE i;
1,088✔
205

206
    if(mode == TPM_ALG_ECB)
1,088✔
207
        return 0;
208
    if(mode == TPM_ALG_CTR)
888✔
209
    {
210
        // The test uses an IV that has 0xff in the last byte
211
        for(i = 1; i <= size; i++)
3,048✔
212
            *iv++ = 0xff - (BYTE)(size - i);
2,848✔
213
    }
214
    else
215
    {
216
        for(i = 0; i < size; i++)
9,936✔
217
            *iv++ = i;
9,248✔
218
    }
219
    return size;
220
}
221

222
//*** TestSymmetricAlgorithm()
223
// Function to test a specific algorithm, key size, and mode.
224
static void TestSymmetricAlgorithm(const SYMMETRIC_TEST_VECTOR* test,  //
730✔
225
                                   TPM_ALG_ID                   mode   //
226
)
227
{
228
    static BYTE     encrypted[MAX_SYM_BLOCK_SIZE * 2];
730✔
229
    static BYTE     decrypted[MAX_SYM_BLOCK_SIZE * 2];
730✔
230
    static TPM2B_IV iv;
730✔
231

232
    // libtpms added begin
233
    if (test->dataOut[mode - TPM_ALG_CTR] == NULL)
730✔
234
        return;
235
    /* Skip test cases whose algorithms or keysizes are runtime-disabled */
236
    if (!RuntimeAlgorithmKeySizeCheckEnabled(&g_RuntimeProfile.RuntimeAlgorithm,
664✔
237
                                             test->alg, test->keyBits,
664✔
238
                                             TPM_ECC_NONE,
239
                                             g_RuntimeProfile.stateFormatLevel))
240
        return;
241
    // libtpms added end
242

243
    //
244
    // Get the appropriate IV
245
    iv.t.size = (UINT16)MakeIv(mode, test->ivSize, iv.t.buffer);
544✔
246

247
    // Encrypt known data
248
    CryptSymmetricEncrypt(encrypted,
544✔
249
                          test->alg,
544✔
250
                          test->keyBits,
544✔
251
                          test->key,
544✔
252
                          &iv,
253
                          mode,
254
                          test->dataInOutSize,
544✔
255
                          test->dataIn);
544✔
256
    // Check that it matches the expected value
257
    if(!MemoryEqual(
544✔
258
           encrypted, test->dataOut[mode - TPM_ALG_CTR], test->dataInOutSize))
544✔
259
        SELF_TEST_FAILURE;
×
260
    // Reinitialize the iv for decryption
261
    MakeIv(mode, test->ivSize, iv.t.buffer);
544✔
262
    CryptSymmetricDecrypt(decrypted,
544✔
263
                          test->alg,
544✔
264
                          test->keyBits,
544✔
265
                          test->key,
544✔
266
                          &iv,
267
                          mode,
268
                          test->dataInOutSize,
544✔
269
                          test->dataOut[mode - TPM_ALG_CTR]);
544✔
270
    // Make sure that it matches what we started with
271
    if(!MemoryEqual(decrypted, test->dataIn, test->dataInOutSize))
544✔
272
        SELF_TEST_FAILURE;
×
273
}
274

275
//*** AllSymsAreDone()
276
// Checks if both symmetric algorithms have been tested. This is put here
277
// so that addition of a symmetric algorithm will be relatively easy to handle.
278
//
279
//  Return Type: BOOL
280
//      TRUE(1)         all symmetric algorithms tested
281
//      FALSE(0)        not all symmetric algorithms tested
282
static BOOL AllSymsAreDone(ALGORITHM_VECTOR* toTest)
45✔
283
{
284
    return (!TEST_BOTH(TPM_ALG_AES) && !TEST_BOTH(TPM_ALG_SM4));
45✔
285
}
286

287
//*** AllModesAreDone()
288
// Checks if all the modes have been tested.
289
//
290
//  Return Type: BOOL
291
//      TRUE(1)         all modes tested
292
//      FALSE(0)        all modes not tested
293
static BOOL AllModesAreDone(ALGORITHM_VECTOR* toTest)
8✔
294
{
295
    TPM_ALG_ID alg;
8✔
296
    for(alg = SYM_MODE_FIRST; alg <= SYM_MODE_LAST; alg++)
32✔
297
        if(TEST_BOTH(alg))
40✔
298
            return FALSE;
299
    return TRUE;
300
}
301

302
//*** TestSymmetric()
303
// If 'alg' is a symmetric block cipher, then all of the modes that are selected are
304
// tested. If 'alg' is a mode, then all algorithms of that mode are tested.
305
static TPM_RC TestSymmetric(TPM_ALG_ID alg, ALGORITHM_VECTOR* toTest)
53✔
306
{
307
    SYM_INDEX  index;
53✔
308
    TPM_ALG_ID mode;
53✔
309
    //
310
    if(!TEST_BIT(alg, *toTest))
53✔
311
        return TPM_RC_SUCCESS;
312
    if(alg == TPM_ALG_AES || alg == TPM_ALG_SM4 || alg == TPM_ALG_CAMELLIA || alg == TPM_ALG_TDES)        // libtpms added TPM_ALG_TDES
53✔
313
    {
314
        // Will test the algorithm for all modes and key sizes
315
        CLEAR_BOTH(alg);
45✔
316

317
        // A test this algorithm for all modes
318
        for(index = 0; index < NUM_SYMS; index++)
495✔
319
        {
320
            if(c_symTestValues[index].alg == alg)
450✔
321
            {
322
                for(mode = SYM_MODE_FIRST; mode <= SYM_MODE_LAST; mode++)
876✔
323
                {
324
                    if(TEST_BIT(mode, g_implementedAlgorithms)) // libtpms always test implemented modes
730✔
325
                        TestSymmetricAlgorithm(&c_symTestValues[index], mode);
730✔
326
                }
327
            }
328
        }
329
        // if all the symmetric tests are done
330
        if(AllSymsAreDone(toTest))
45✔
331
        {
332
            // all symmetric algorithms tested so no modes should be set
333
            for(alg = SYM_MODE_FIRST; alg <= SYM_MODE_LAST; alg++)
204✔
334
                CLEAR_BOTH(alg);
170✔
335
        }
336
    }
337
    else if(SYM_MODE_FIRST <= alg && alg <= SYM_MODE_LAST)
338
    {
339
        // Test this mode for all key sizes and algorithms
340
        for(index = 0; index < NUM_SYMS; index++)
88✔
341
        {
342
            // The mode testing only comes into play when doing self tests
343
            // by command. When doing self tests by command, the block ciphers are
344
            // tested first. That means that all of their modes would have been
345
            // tested for all key sizes. If there is no block cipher left to
346
            // test, then clear this mode bit.
347
            if(!TEST_BIT(TPM_ALG_AES, *toTest) && !TEST_BIT(TPM_ALG_SM4, *toTest))
80✔
348
            {
349
                CLEAR_BOTH(alg);
80✔
350
            }
351
            else
352
            {
353
                for(index = 0; index < NUM_SYMS; index++)
×
354
                {
355
                    if(TEST_BIT(c_symTestValues[index].alg, *toTest))
×
356
                        TestSymmetricAlgorithm(&c_symTestValues[index], alg);
×
357
                }
358
                // have tested this mode for all algorithms
359
                CLEAR_BOTH(alg);
80✔
360
            }
361
        }
362
        if(AllModesAreDone(toTest))
8✔
363
        {
364
            CLEAR_BOTH(TPM_ALG_AES);
×
365
            CLEAR_BOTH(TPM_ALG_SM4);
×
366
        }
367
    }
368
    else
369
        pAssert(alg == 0 && alg != 0);
×
370
    return TPM_RC_SUCCESS;
371
}
372

373
//** RSA Tests
374
#  if ALG_RSA
375

376
//*** Introduction
377
// The tests are for public key only operations and for private key operations.
378
// Signature verification and encryption are public key operations. They are tested
379
// by using a KVT. For signature verification, this means that a known good
380
// signature is checked by CryptRsaValidateSignature(). If it fails, then the
381
// TPM enters failure mode. For encryption, the TPM encrypts known values using
382
// the selected scheme and checks that the returned value matches the expected
383
// value.
384
//
385
// For private key operations, a full scheme check is used. For a signing key, a
386
// known key is used to sign a known message. Then that signature is verified.
387
// since the signature may involve use of random values, the signature will be
388
// different each time and we can't always check that the signature matches a
389
// known value. The same technique is used for decryption (RSADP/RSAEP).
390
//
391
// When an operation uses the public key and the verification has not been
392
// tested, the TPM will do a KVT.
393
//
394
// The test for the signing algorithm is built into the call for the algorithm
395

396
//*** RsaKeyInitialize()
397
// The test key is defined by a public modulus and a private prime. The TPM's RSA
398
// code computes the second prime and the private exponent.
399
static void RsaKeyInitialize(OBJECT* testObject)
89✔
400
{
401
    MemoryCopy2B(&testObject->publicArea.unique.rsa.b,
89✔
402
                 (P2B)&c_rsaPublicModulus,
403
                 sizeof(c_rsaPublicModulus));
404
    MemoryCopy2B(&testObject->sensitive.sensitive.rsa.b,
89✔
405
                 (P2B)&c_rsaPrivatePrime,
406
                 sizeof(testObject->sensitive.sensitive.rsa.t.buffer));
407
    testObject->publicArea.parameters.rsaDetail.keyBits = RSA_TEST_KEY_SIZE * 8;
89✔
408
    // Use the default exponent
409
    testObject->publicArea.parameters.rsaDetail.exponent = 0;
89✔
410
    testObject->attributes.privateExp = 0;                        // libtpms: keep
89✔
411
}
89✔
412

413
//*** TestRsaEncryptDecrypt()
414
// These tests are for a public key encryption that uses a random value.
415
static TPM_RC TestRsaEncryptDecrypt(TPM_ALG_ID        scheme,  // IN: the scheme
52✔
416
                                    ALGORITHM_VECTOR* toTest   //
417
)
418
{
419
    static TPM2B_PUBLIC_KEY_RSA testInput;
52✔
420
    static TPM2B_PUBLIC_KEY_RSA testOutput;
52✔
421
    static OBJECT               testObject;
52✔
422
    const TPM2B_RSA_TEST_KEY*   kvtValue  = NULL;
52✔
423
    TPM_RC                      result    = TPM_RC_SUCCESS;
52✔
424
    const TPM2B*                testLabel = NULL;
52✔
425
    TPMT_RSA_DECRYPT            rsaScheme;
52✔
426
    //
427
    // Don't need to initialize much of the test object
428
    testObject.attributes.privateExp = CLEAR;                        // libtpms: keep
52✔
429
    RsaKeyInitialize(&testObject);
52✔
430
    rsaScheme.scheme                 = scheme;
52✔
431
    rsaScheme.details.anySig.hashAlg = DEFAULT_TEST_HASH;
52✔
432
    CLEAR_BOTH(scheme);
52✔
433
    CLEAR_BOTH(TPM_ALG_NULL);
52✔
434
    if(scheme == TPM_ALG_NULL)
52✔
435
    {
436
        if (RuntimeProfileRequiresAttributeFlags(&g_RuntimeProfile,        // libtpms added begin
27✔
437
                                                 RUNTIME_ATTRIBUTE_NO_UNPADDED_ENCRYPTION))
438
            return TPM_RC_SUCCESS;        // don't test NULL with RSA        // libtpms added end
439
        // This is an encryption scheme using the private key without any encoding.
440
        memcpy(testInput.t.buffer, c_RsaTestValue, sizeof(c_RsaTestValue));
27✔
441
        testInput.t.size = sizeof(c_RsaTestValue);
27✔
442
        if(TPM_RC_SUCCESS
27✔
443
           != CryptRsaEncrypt(
27✔
444
               &testOutput, &testInput.b, &testObject, &rsaScheme, NULL, NULL))
445
            SELF_TEST_FAILURE;
×
446
        if(!MemoryEqual(testOutput.t.buffer, c_RsaepKvt.buffer, c_RsaepKvt.size))
27✔
447
            SELF_TEST_FAILURE;
×
448
        MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
27✔
449
        if(TPM_RC_SUCCESS
27✔
450
           != CryptRsaDecrypt(
27✔
451
               &testOutput.b, &testInput.b, &testObject, &rsaScheme, NULL))
452
            SELF_TEST_FAILURE;
×
453
        if(!MemoryEqual(testOutput.t.buffer, c_RsaTestValue, sizeof(c_RsaTestValue)))
27✔
454
            SELF_TEST_FAILURE;
×
455
    }
456
    else
457
    {
458
        // TPM_ALG_RSAES:
459
        // This is an decryption scheme using padding according to
460
        // PKCS#1v2.1, 7.2. This padding uses random bits. To test a public
461
        // key encryption that uses random data, encrypt a value and then
462
        // decrypt the value and see that we get the encrypted data back.
463
        // The hash is not used by this encryption so it can be TMP_ALG_NULL
464

465
        // TPM_ALG_OAEP:
466
        // This is also an decryption scheme and it also uses a
467
        // pseudo-random
468
        // value. However, this also uses a hash algorithm. So, we may need
469
        // to test that algorithm before use.
470
        if(scheme == TPM_ALG_OAEP)
25✔
471
        {
472
            TEST_DEFAULT_TEST_HASH(toTest);
13✔
473
            kvtValue  = &c_OaepKvt;
13✔
474
            testLabel = OAEP_TEST_STRING;
13✔
475
        }
476
        else if(scheme == TPM_ALG_RSAES)
12✔
477
        {
478
            kvtValue  = &c_RsaesKvt;
479
            testLabel = NULL;
480
        }
481
        else
482
            SELF_TEST_FAILURE;
×
483
        // Only use a digest-size portion of the test value
484
        memcpy(testInput.t.buffer, c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE);
25✔
485
        testInput.t.size = DEFAULT_TEST_DIGEST_SIZE;
25✔
486

487
        // See if the encryption works
488
        if(TPM_RC_SUCCESS
25✔
489
           != CryptRsaEncrypt(
25✔
490
               &testOutput, &testInput.b, &testObject, &rsaScheme, testLabel, NULL))
491
            SELF_TEST_FAILURE;
×
492
        MemoryCopy2B(&testInput.b, &testOutput.b, sizeof(testInput.t.buffer));
25✔
493
        // see if we can decrypt this value and get the original data back
494
        if(TPM_RC_SUCCESS
25✔
495
           != CryptRsaDecrypt(
25✔
496
               &testOutput.b, &testInput.b, &testObject, &rsaScheme, testLabel))
497
            SELF_TEST_FAILURE;
×
498
        // See if the results compare
499
        if(testOutput.t.size != DEFAULT_TEST_DIGEST_SIZE
25✔
500
           || !MemoryEqual(
25✔
501
               testOutput.t.buffer, c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE))
502
            SELF_TEST_FAILURE;
×
503
        // Now check that the decryption works on a known value
504
        MemoryCopy2B(&testInput.b, (P2B)kvtValue, sizeof(testInput.t.buffer));
25✔
505
        if(TPM_RC_SUCCESS
25✔
506
           != CryptRsaDecrypt(
25✔
507
               &testOutput.b, &testInput.b, &testObject, &rsaScheme, testLabel))
508
            SELF_TEST_FAILURE;
×
509
        if(testOutput.t.size != DEFAULT_TEST_DIGEST_SIZE
25✔
510
           || !MemoryEqual(
25✔
511
               testOutput.t.buffer, c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE))
512
            SELF_TEST_FAILURE;
×
513
    }
514
    return result;
515
}
516

517
//*** TestRsaSignAndVerify()
518
// This function does the testing of the RSA sign and verification functions. This
519
// test does a KVT.
520
static TPM_RC TestRsaSignAndVerify(TPM_ALG_ID scheme, ALGORITHM_VECTOR* toTest)
37✔
521
{
522
    TPM_RC                result = TPM_RC_SUCCESS;
37✔
523
    static OBJECT         testObject;
37✔
524
    static TPM2B_DIGEST   testDigest;
37✔
525
    static TPMT_SIGNATURE testSig;
37✔
526

527
    // Do a sign and signature verification.
528
    // RSASSA:
529
    // This is a signing scheme according to PKCS#1-v2.1 8.2. It does not
530
    // use random data so there is a KVT for the signing operation. On
531
    // first use of the scheme for signing, use the TPM's RSA key to
532
    // sign a portion of c_RsaTestData and compare the results to c_RsassaKvt. Then
533
    // decrypt the data to see that it matches the starting value. This verifies
534
    // the signature with a KVT
535

536
    // Clear the bits indicating that the function has not been checked. This is to
537
    // prevent looping
538
    CLEAR_BOTH(scheme);
37✔
539
    CLEAR_BOTH(TPM_ALG_NULL);
37✔
540
    CLEAR_BOTH(TPM_ALG_RSA);
37✔
541

542
    RsaKeyInitialize(&testObject);
37✔
543
    memcpy(testDigest.t.buffer, (BYTE*)c_RsaTestValue, DEFAULT_TEST_DIGEST_SIZE);
37✔
544
    testDigest.t.size             = DEFAULT_TEST_DIGEST_SIZE;
37✔
545
    testSig.sigAlg                = scheme;
37✔
546
    testSig.signature.rsapss.hash = DEFAULT_TEST_HASH;
37✔
547

548
    // RSAPSS:
549
    // This is a signing scheme a according to PKCS#1-v2.2 8.1 it uses
550
    // random data in the signature so there is no KVT for the signing
551
    // operation. To test signing, the TPM will use the TPM's RSA key
552
    // to sign a portion of c_RsaTestValue and then it will verify the
553
    // signature. For verification, c_RsapssKvt is verified before the
554
    // user signature blob is verified. The worst case for testing of this
555
    // algorithm is two private and one public key operation.
556

557
    // The process is to sign known data. If RSASSA is being done, verify that the
558
    // signature matches the precomputed value. For both, use the signed value and
559
    // see that the verification says that it is a good signature. Then
560
    // if testing RSAPSS, do a verify of a known good signature. This ensures that
561
    // the validation function works.
562

563
    if(TPM_RC_SUCCESS != CryptRsaSign(&testSig, &testObject, &testDigest, NULL))
37✔
564
        SELF_TEST_FAILURE;
×
565
    // For RSASSA, make sure the results is what we are looking for
566
    if(testSig.sigAlg == TPM_ALG_RSASSA)
37✔
567
    {
568
        if(testSig.signature.rsassa.sig.t.size != RSA_TEST_KEY_SIZE
25✔
569
           || !MemoryEqual(c_RsassaKvt.buffer,
25✔
570
                           testSig.signature.rsassa.sig.t.buffer,
571
                           RSA_TEST_KEY_SIZE))
572
            SELF_TEST_FAILURE;
×
573
    }
574
    // See if the TPM will validate its own signatures
575
    if(TPM_RC_SUCCESS
37✔
576
       != CryptRsaValidateSignature(&testSig, &testObject, &testDigest))
37✔
577
        SELF_TEST_FAILURE;
×
578
    // If this is RSAPSS, check the verification with known signature
579
    // Have to copy because  CrytpRsaValidateSignature() eats the signature
580
    if(TPM_ALG_RSAPSS == scheme)
37✔
581
    {
582
        MemoryCopy2B(&testSig.signature.rsapss.sig.b,
12✔
583
                     (P2B)&c_RsapssKvt,
584
                     sizeof(testSig.signature.rsapss.sig.t.buffer));
585
        if(TPM_RC_SUCCESS
12✔
586
           != CryptRsaValidateSignature(&testSig, &testObject, &testDigest))
12✔
587
            SELF_TEST_FAILURE;
×
588
    }
589
    return result;
37✔
590
}
591

592
//*** TestRSA()
593
// Function uses the provided vector to indicate which tests to run. It will clear
594
// the vector after each test is run and also clear g_toTest
595
static TPM_RC TestRsa(TPM_ALG_ID alg, ALGORITHM_VECTOR* toTest)
89✔
596
{
597
    TPM_RC result = TPM_RC_SUCCESS;
89✔
598
    //
599
    switch(alg)
89✔
600
    {
601
        case TPM_ALG_NULL:
27✔
602
            // This is the RSAEP/RSADP function. If we are processing a list, don't
603
            // need to test these now because any other test will validate
604
            // RSAEP/RSADP. Can tell this is list of test by checking to see if
605
            // 'toTest' is pointing at g_toTest. If so, this is an isolated test
606
            // an need to go ahead and do the test;
607
            if((toTest == &g_toTest)
27✔
608
               || (!TEST_BIT(TPM_ALG_RSASSA, *toTest)
20✔
609
                   && !TEST_BIT(TPM_ALG_RSAES, *toTest)
20✔
610
                   && !TEST_BIT(TPM_ALG_RSAPSS, *toTest)
20✔
611
                   && !TEST_BIT(TPM_ALG_OAEP, *toTest)))
20✔
612
                // Not running a list of tests or no other tests on the list
613
                // so run the test now
614
                result = TestRsaEncryptDecrypt(alg, toTest);
27✔
615
            // if not running the test now, leave the bit on, just in case things
616
            // get interrupted
617
            break;
618
        case TPM_ALG_OAEP:
25✔
619
        case TPM_ALG_RSAES:
620
            result = TestRsaEncryptDecrypt(alg, toTest);
25✔
621
            break;
25✔
622
        case TPM_ALG_RSAPSS:
37✔
623
        case TPM_ALG_RSASSA:
624
            result = TestRsaSignAndVerify(alg, toTest);
37✔
625
            break;
37✔
626
        default:
×
627
            SELF_TEST_FAILURE;
×
628
    }
629
    return result;
89✔
630
}
631

632
#  endif  // ALG_RSA
633

634
//** ECC Tests
635

636
#  if ALG_ECC
637

638
//*** LoadEccParameter()
639
// This function is mostly for readability and type checking
640
static void LoadEccParameter(TPM2B_ECC_PARAMETER* to,   // target
359✔
641
                             const TPM2B_EC_TEST* from  // source
642
)
643
{
644
    MemoryCopy2B(&to->b, &from->b, sizeof(to->t.buffer));
359✔
645
}
70✔
646

647
//*** LoadEccPoint()
648
static void LoadEccPoint(TPMS_ECC_POINT*      point,  // target
289✔
649
                         const TPM2B_EC_TEST* x,      // source
650
                         const TPM2B_EC_TEST* y)
651
{
652
    MemoryCopy2B(&point->x.b, (TPM2B*)x, sizeof(point->x.t.buffer));
289✔
653
    MemoryCopy2B(&point->y.b, (TPM2B*)y, sizeof(point->y.t.buffer));
289✔
654
}
289✔
655

656
//*** TestECDH()
657
// This test does a KVT on a point multiply.
658
static TPM_RC TestECDH(TPM_ALG_ID        scheme,  // IN: for consistency
219✔
659
                       ALGORITHM_VECTOR* toTest  // IN/OUT: modified after test is run
660
)
661
{
662
    static TPMS_ECC_POINT      Z;
219✔
663
    static TPMS_ECC_POINT      Qe;
219✔
664
    static TPM2B_ECC_PARAMETER ds;
219✔
665
    TPM_RC                     result = TPM_RC_SUCCESS;
219✔
666
    //
667
    NOT_REFERENCED(scheme);
219✔
668
    CLEAR_BOTH(TPM_ALG_ECDH);
219✔
669
    LoadEccParameter(&ds, &c_ecTestKey_ds);
219✔
670
    LoadEccPoint(&Qe, &c_ecTestKey_QeX, &c_ecTestKey_QeY);
219✔
671
    if(TPM_RC_SUCCESS != CryptEccPointMultiply(&Z, c_testCurve, &Qe, &ds, NULL, NULL))
219✔
672
        SELF_TEST_FAILURE;
×
673
    if(!MemoryEqual2B(&c_ecTestEcdh_X.b, &Z.x.b)
219✔
674
       || !MemoryEqual2B(&c_ecTestEcdh_Y.b, &Z.y.b))
219✔
675
        SELF_TEST_FAILURE;
×
676
    return result;
219✔
677
}
678

679
//*** TestEccSignAndVerify()
680
static TPM_RC TestEccSignAndVerify(TPM_ALG_ID scheme, ALGORITHM_VECTOR* toTest)
70✔
681
{
682
    static OBJECT          testObject;
70✔
683
    static TPMT_SIGNATURE  testSig;
70✔
684
    static TPMT_ECC_SCHEME eccScheme;
70✔
685

686
    testSig.sigAlg                   = scheme;
70✔
687
    testSig.signature.ecdsa.hash     = DEFAULT_TEST_HASH;
70✔
688

689
    eccScheme.scheme                 = scheme;
70✔
690
    eccScheme.details.anySig.hashAlg = DEFAULT_TEST_HASH;
70✔
691

692
    CLEAR_BOTH(scheme);
70✔
693
    CLEAR_BOTH(TPM_ALG_ECDH);
70✔
694

695
    // ECC signature verification testing uses a KVT.
696
    switch(scheme)
70✔
697
    {
698
        case TPM_ALG_ECDSA:
699
            LoadEccParameter(&testSig.signature.ecdsa.signatureR, &c_TestEcDsa_r);
59✔
700
            LoadEccParameter(&testSig.signature.ecdsa.signatureS, &c_TestEcDsa_s);
59✔
701
            break;
702
        case TPM_ALG_ECSCHNORR:
703
            LoadEccParameter(&testSig.signature.ecschnorr.signatureR,
11✔
704
                             &c_TestEcSchnorr_r);
705
            LoadEccParameter(&testSig.signature.ecschnorr.signatureS,
11✔
706
                             &c_TestEcSchnorr_s);
707
            break;
708
        case TPM_ALG_SM2:
709
            // don't have a test for SM2
710
            return TPM_RC_SUCCESS;
711
        default:
×
712
            SELF_TEST_FAILURE;
×
713
            break;
70✔
714
    }
715
    TEST_DEFAULT_TEST_HASH(toTest);
70✔
716

717
    // Have to copy the key. This is because the size used in the test vectors
718
    // is the size of the ECC parameter for the test key while the size of a point
719
    // is TPM dependent
720
    MemoryCopy2B(&testObject.sensitive.sensitive.ecc.b,
70✔
721
                 &c_ecTestKey_ds.b,
722
                 sizeof(testObject.sensitive.sensitive.ecc.t.buffer));
723
    LoadEccPoint(
70✔
724
        &testObject.publicArea.unique.ecc, &c_ecTestKey_QsX, &c_ecTestKey_QsY);
725
    testObject.publicArea.parameters.eccDetail.curveID = c_testCurve;
70✔
726

727
    if(TPM_RC_SUCCESS
70✔
728
       != CryptEccValidateSignature(
70✔
729
           &testSig, &testObject, (TPM2B_DIGEST*)&c_ecTestValue.b))
730
    {
731
        SELF_TEST_FAILURE;
×
732
    }
733
    CHECK_CANCELED;
70✔
734

735
    // Now sign and verify some data
736
    if(TPM_RC_SUCCESS
70✔
737
       != CryptEccSign(
70✔
738
           &testSig, &testObject, (TPM2B_DIGEST*)&c_ecTestValue, &eccScheme, NULL))
739
        SELF_TEST_FAILURE;
×
740

741
    CHECK_CANCELED;
70✔
742

743
    if(TPM_RC_SUCCESS
70✔
744
       != CryptEccValidateSignature(
70✔
745
           &testSig, &testObject, (TPM2B_DIGEST*)&c_ecTestValue))
746
        SELF_TEST_FAILURE;
×
747

748
    CHECK_CANCELED;
70✔
749

750
    return TPM_RC_SUCCESS;
751
}
752

753
//*** TestKDFa()
754
static TPM_RC TestKDFa(ALGORITHM_VECTOR* toTest)
66✔
755
{
756
    static TPM2B_KDF_TEST_KEY keyOut;
66✔
757
    UINT32                    counter = 0;
66✔
758
    //
759
    CLEAR_BOTH(TPM_ALG_KDF1_SP800_108);
66✔
760

761
    keyOut.t.size = CryptKDFa(KDF_TEST_ALG,
66✔
762
                              &c_kdfTestKeyIn.b,
763
                              &c_kdfTestLabel.b,
764
                              &c_kdfTestContextU.b,
765
                              &c_kdfTestContextV.b,
766
                              TEST_KDF_KEY_SIZE * 8,
767
                              keyOut.t.buffer,
768
                              &counter,
769
                              FALSE);
770
    if(keyOut.t.size != TEST_KDF_KEY_SIZE
66✔
771
       || !MemoryEqual(keyOut.t.buffer, c_kdfTestKeyOut.t.buffer, TEST_KDF_KEY_SIZE))
66✔
772
        SELF_TEST_FAILURE;
×
773

774
    return TPM_RC_SUCCESS;
66✔
775
}
776

777
//*** TestEcc()
778
static TPM_RC TestEcc(TPM_ALG_ID alg, ALGORITHM_VECTOR* toTest)
289✔
779
{
780
    TPM_RC result = TPM_RC_SUCCESS;
289✔
781
    NOT_REFERENCED(toTest);
289✔
782
    switch(alg)
289✔
783
    {
784
        case TPM_ALG_ECC:
219✔
785
        case TPM_ALG_ECDH:
786
            // If this is in a loop then see if another test is going to deal with
787
            // this.
788
            // If toTest is not a self-test list
789
            if((toTest == &g_toTest)
219✔
790
               // or this is the only ECC test in the list
791
               || !(TEST_BIT(TPM_ALG_ECDSA, *toTest)
×
792
                    || TEST_BIT(TPM_ALG_ECSCHNORR, *toTest)   // libtpms: fixed
×
793
                    || TEST_BIT(TPM_ALG_SM2, *toTest)))
×
794
            {
795
                result = TestECDH(alg, toTest);
219✔
796
            }
797
            break;
798
        case TPM_ALG_ECDSA:
70✔
799
        case TPM_ALG_ECSCHNORR:
800
        case TPM_ALG_SM2:
801
            result = TestEccSignAndVerify(alg, toTest);
70✔
802
            break;
70✔
803
        default:
×
804
            SELF_TEST_FAILURE;
×
805
            break;
289✔
806
    }
807
    return result;
289✔
808
}
809

810
#  endif  // ALG_ECC
811

812
//*** TestAlgorithm()
813
// Dispatches to the correct test function for the algorithm or gets a list of
814
// testable algorithms.
815
//
816
// If 'toTest' is not NULL, then the test decisions are based on the algorithm
817
// selections in 'toTest'. Otherwise, 'g_toTest' is used. When bits are clear in
818
// 'g_toTest' they will also be cleared 'toTest'.
819
//
820
// If there doesn't happen to be a test for the algorithm, its associated bit is
821
// quietly cleared.
822
//
823
// If 'alg' is zero (TPM_ALG_ERROR), then the toTest vector is cleared of any bits
824
// for which there is no test (i.e. no tests are actually run but the vector is
825
// cleared).
826
//
827
// Note: 'toTest' will only ever have bits set for implemented algorithms but 'alg'
828
// can be anything.
829
//
830
//  Return Type: TPM_RC
831
//      TPM_RC_CANCELED     test was canceled
832
LIB_EXPORT
833
TPM_RC
834
TestAlgorithm(TPM_ALG_ID alg, ALGORITHM_VECTOR* toTest)
22,399✔
835
{
836
    TPM_ALG_ID first  = (alg == TPM_ALG_ERROR) ? TPM_ALG_FIRST : alg;
22,399✔
837
    TPM_ALG_ID last   = (alg == TPM_ALG_ERROR) ? TPM_ALG_LAST : alg;
22,399✔
838
    BOOL       doTest = (alg != TPM_ALG_ERROR);
22,399✔
839
    TPM_RC     result = TPM_RC_SUCCESS;
22,399✔
840

841
    if(toTest == NULL)
22,399✔
842
        toTest = &g_toTest;
9,626✔
843

844
    // This is kind of strange. This function will either run a test of the selected
845
    // algorithm or just clear a bit if there is no test for the algorithm. So,
846
    // either this loop will be executed once for the selected algorithm or once for
847
    // each of the possible algorithms. If it is executed more than once ('alg' ==
848
    // ALG_ERROR), then no test will be run but bits will be cleared for
849
    // unimplemented algorithms. This was done this way so that there is only one
850
    // case statement with all of the algorithms. It was easier to have one case
851
    // statement than to have multiple ones to manage whenever an algorithm ID is
852
    // added.
853
    for(alg = first; (alg <= last); alg++)
1,441,326✔
854
    {
855
        // if 'alg' was TPM_ALG_ERROR, then we will be cycling through
856
        // values, some of which may not be implemented. If the bit in toTest
857
        // happens to be set, then we could either generated an assert, or just
858
        // silently CLEAR it. Decided to just clear.
859
        if(!TEST_BIT(alg, g_implementedAlgorithms))
1,418,927✔
860
        {
861
            CLEAR_BIT(alg, *toTest);
998,294✔
862
            continue;
998,294✔
863
        }
864
        // Process whatever is left.
865
        // NOTE: since this switch will only be called if the algorithm is
866
        // implemented, it is not necessary to modify this list except to comment
867
        // out the algorithms for which there is no test
868
        switch(alg)
420,633✔
869
        {
870
            // Symmetric block ciphers
871
#  if ALG_AES
872
            case TPM_ALG_AES:
12,491✔
873
// libtpms added begin
874
#  if SMAC_IMPLEMENTED && ALG_CMAC
875
                if (doTest)
12,491✔
876
                {
877
                    result = TestSMAC(toTest);
23✔
878
                    if (result != TPM_RC_SUCCESS)
23✔
879
                        break;
880
                }
881
#  endif
882
// libtpms added end
883
#  endif
884
#  if ALG_SM4
885
                // if SM4 is implemented, its test is like other block ciphers but there
886
                // aren't any test vectors for it yet
887
            case TPM_ALG_SM4: /* libtpms changed */
888
#  endif  // ALG_SM4
889
#  if ALG_CAMELLIA
890
            /* fallthrough */
891
            case TPM_ALG_CAMELLIA:  // libtpms activated
892
#  endif
893
#  if ALG_TDES
894
            case TPM_ALG_TDES:      // libtpms added
895
#  endif
896
            // Symmetric modes
897
#  if !ALG_CFB
898
#    error CFB is required in all TPM implementations
899
#  endif  // !ALG_CFB
900
            case TPM_ALG_CFB:
901
                if(doTest)
49,791✔
902
                    result = TestSymmetric(alg, toTest);
45✔
903
                break;
904
#  if ALG_CTR
905
            case TPM_ALG_CTR:
49,842✔
906
#  endif  // ALG_CRT
907
#  if ALG_OFB
908
            case TPM_ALG_OFB:
909
#  endif  // ALG_OFB
910
#  if ALG_CBC
911
            case TPM_ALG_CBC:
912
#  endif  // ALG_CBC
913
#  if ALG_ECB
914
            case TPM_ALG_ECB:
915
#  endif
916
                if(doTest)
49,842✔
917
                    result = TestSymmetric(alg, toTest);
8✔
918
                else
919
                    // If doing the initialization of g_toTest vector, only need
920
                    // to test one of the modes for the symmetric algorithms. If
921
                    // initializing for a SelfTest(FULL_TEST), allow all the modes.
922
                    if(toTest == &g_toTest)
49,834✔
923
                        CLEAR_BIT(alg, *toTest);
49,834✔
924
                break;
925
#  if !ALG_HMAC
926
#    error HMAC is required in all TPM implementations
927
#  endif
928
            case TPM_ALG_HMAC:
12,475✔
929
                // Clear the bit that indicates that HMAC is required because
930
                // HMAC is used as the basic test for all hash algorithms.
931
                CLEAR_BOTH(alg);
12,475✔
932
                // Testing HMAC means test the default hash
933
                if(doTest)
12,475✔
934
                    TestHash(DEFAULT_TEST_HASH, toTest);
7✔
935
                else
936
                    // If not testing, then indicate that the hash needs to be
937
                    // tested because this uses HMAC
938
                    SET_BOTH(DEFAULT_TEST_HASH);
12,468✔
939
                break;
940
// Have to use two arguments for the macro even though only the first is used in the
941
// expansion.
942
#  define HASH_CASE_TEST(HASH, hash) case ALG_##HASH##_VALUE:
943
                FOR_EACH_HASH(HASH_CASE_TEST)
59,070✔
944
#  undef HASH_CASE_TEST
945
                if(doTest)
59,070✔
946
                    result = TestHash(alg, toTest);
9,348✔
947
                break;
948
                // RSA-dependent
949
#  if ALG_RSA
950
            case TPM_ALG_RSA:
12,495✔
951
                CLEAR_BOTH(alg);
12,495✔
952
                if(doTest)
12,495✔
953
                    result = TestRsa(TPM_ALG_NULL, toTest);
27✔
954
                else
955
                    SET_BOTH(TPM_ALG_NULL);
12,468✔
956
                break;
957
            case TPM_ALG_RSASSA:
49,738✔
958
            case TPM_ALG_RSAES:
959
            case TPM_ALG_RSAPSS:
960
            case TPM_ALG_OAEP:
961
            case TPM_ALG_NULL:  // used or RSADP
962
                if(doTest)
49,738✔
963
                    result = TestRsa(alg, toTest);
62✔
964
                break;
965
#  endif  // ALG_RSA
966
#  if ALG_KDF1_SP800_108
967
            case TPM_ALG_KDF1_SP800_108:
12,534✔
968
                if(doTest)
12,534✔
969
                    result = TestKDFa(toTest);
66✔
970
                break;
971
#  endif  // ALG_KDF1_SP800_108
972
#  if ALG_ECC
973
                // ECC dependent but no tests
974
                //        case TPM_ALG_ECDAA:
975
                //        case TPM_ALG_ECMQV:
976
                //        case TPM_ALG_KDF1_SP800_56a:
977
                //        case TPM_ALG_KDF2:
978
                //        case TPM_ALG_MGF1:
979
            case TPM_ALG_ECC:
12,475✔
980
                CLEAR_BOTH(alg);
12,475✔
981
                if(doTest)
12,475✔
982
                    result = TestEcc(TPM_ALG_ECDH, toTest);
7✔
983
                else
984
                    SET_BOTH(TPM_ALG_ECDH);
12,468✔
985
                break;
986
            case TPM_ALG_ECDSA:
37,634✔
987
            case TPM_ALG_ECDH:
988
            case TPM_ALG_ECSCHNORR:
989
                //            case TPM_ALG_SM2:
990
                if(doTest)
37,634✔
991
                    result = TestEcc(alg, toTest);
282✔
992
                break;
993
#  endif  // ALG_ECC
994
            default:
124,579✔
995
                CLEAR_BIT(alg, *toTest);
124,579✔
996
                break;
124,579✔
997
        }
998
        if(result != TPM_RC_SUCCESS)
420,633✔
999
            break;
1000
    }
1001
    return result;
22,399✔
1002
}
1003

1004
#endif  // SELF_TESTS
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