Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/libmain.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// libmain.c
3
// General routines for the SymCrypt library
4
//
5
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
6
//
7
8
#include "precomp.h"
9
10
#include "C_asm_shared.inc"
11
12
#include "buildInfo.h"
13
14
// The following global g_SymCryptFlags has to be at least 32
15
// bits because the iOS environment has interlocked function
16
// support for variables of size at least 32 bits.
17
// The relevant function is OSAtomicOr32Barrier.
18
UINT32 g_SymCryptFlags = 0;
19
20
SYMCRYPT_CPU_FEATURES g_SymCryptCpuFeaturesNotPresent = (SYMCRYPT_CPU_FEATURES) ~0;
21
SYMCRYPT_CPU_FEATURES g_SymCryptCpuFeaturesPresentCheck = 0;
22
23
#if SYMCRYPT_DEBUG
24
25
SYMCRYPT_NOINLINE
26
VOID
27
SYMCRYPT_CALL
28
SymCryptLibraryWasNotInitialized(void)
29
0
{
30
0
    SymCryptFatal( 'init' );    // Function name helps figure out what the problem is.
31
0
}
32
33
#endif
34
35
const CHAR * const SymCryptBuildString =
36
        "v" SYMCRYPT_BUILD_INFO_VERSION
37
        "_" SYMCRYPT_BUILD_INFO_BRANCH
38
        "_" SYMCRYPT_BUILD_INFO_COMMIT
39
        "_" SYMCRYPT_BUILD_INFO_TIMESTAMP;
40
41
VOID
42
SYMCRYPT_CALL
43
SymCryptInitEnvCommon( UINT32 version )
44
// Returns TRUE if the initialization steps have to be performed.
45
0
{
46
0
    UINT32 tmp;
47
48
0
    const CHAR * p;
49
50
    // Assertion that verifies that the calling application was compiled with
51
    // the same version header files as the library.
52
0
    if( version != SYMCRYPT_API_VERSION )
53
0
    {
54
0
        SymCryptFatal( 'apiv' );
55
0
    }
56
57
    //
58
    // Use an interlocked to set the flag in case we add other flags
59
    // that are modified by different threads.
60
    //
61
0
    SYMCRYPT_ATOMIC_OR32_PRE_RELAXED( &g_SymCryptFlags, SYMCRYPT_FLAG_LIB_INITIALIZED );
62
63
    //
64
    // Do a forced write of our code version. This ensures that the code
65
    // version is part of the binary, so we can look at a binary and figure
66
    // out which version of SymCrypt it was linked with.
67
    //
68
0
    SYMCRYPT_FORCE_WRITE32( &tmp, SYMCRYPT_API_VERSION );
69
70
    //
71
    // Force the build string to be in memory, because otherwise the
72
    // compiler might get smart and remove it.
73
    // This ensures we can always track back to the SymCrypt source code from
74
    // any binary that links this library
75
    //
76
0
    for( p = SymCryptBuildString; *p!=0; p++ )
77
0
    {
78
0
        SYMCRYPT_FORCE_WRITE8( (PBYTE) &tmp, *p );
79
0
    }
80
81
    //
82
    // Make an inverted copy of the CPU detection results.
83
    // This helps us diagnose corruption of our flags
84
    // Force-write otherwise the compiler optimizes it away
85
    //
86
0
    SYMCRYPT_FORCE_WRITE32( &g_SymCryptCpuFeaturesPresentCheck, ~g_SymCryptCpuFeaturesNotPresent );
87
88
    //
89
    // Test that the C and assembler code agree on the various structure member offsets.
90
    // This gets optimized away in FRE builds as all the values are compile-time computable.
91
    //
92
0
#define SYMCRYPT_CHECK_ASM_OFFSET( a, b ) if( (a) != (b) ) {SymCryptFatal( b );}
93
0
    SYMCRYPT_CHECK_ASM_OFFSETS;
94
0
#undef SYMCRYPT_CHECK_ASM_OFFSET
95
0
}
96
97
_Analysis_noreturn_
98
SYMCRYPT_NOINLINE
99
VOID
100
SYMCRYPT_CALL
101
SymCryptFatalHang( UINT32 fatalCode )
102
//
103
// This function is used by the environment-specific fatal code
104
// as a last resort when none of the other fatal methods work.
105
//
106
0
{
107
0
    UINT32   fcode;
108
109
    //
110
    // Put the fatal code in a location we can find
111
    //
112
0
    SYMCRYPT_FORCE_WRITE32( &fcode, fatalCode );
113
114
0
fatalInfiniteLoop:
115
0
    goto fatalInfiniteLoop;
116
0
}
117
118
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64
119
120
VOID
121
SYMCRYPT_CALL
122
SymCryptWipeAsm( _Out_writes_bytes_( cbData ) PVOID pbData, SIZE_T cbData );
123
124
VOID
125
SYMCRYPT_CALL
126
SymCryptWipe( _Out_writes_bytes_( cbData ) PVOID pbData, SIZE_T cbData )
127
5.84M
{
128
5.84M
    SymCryptWipeAsm( pbData, cbData );
129
5.84M
}
130
131
#else
132
//
133
// Generic but slow wipe routine.
134
//
135
VOID
136
SYMCRYPT_CALL
137
SymCryptWipe( _Out_writes_bytes_( cbData ) PVOID pbData, SIZE_T cbData )
138
{
139
    volatile BYTE * p = (volatile BYTE *) pbData;
140
    SIZE_T i;
141
142
    for( i=0; i<cbData; i++ ){
143
        p[i] = 0;
144
    }
145
146
}
147
#endif
148
149
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_ARM
150
VOID
151
SYMCRYPT_CALL
152
SymCryptXorBytes(
153
    _In_reads_( cbBytes )   PCBYTE  pbSrc1,
154
    _In_reads_( cbBytes )   PCBYTE  pbSrc2,
155
    _Out_writes_( cbBytes ) PBYTE   pbResult,
156
                            SIZE_T  cbBytes )
157
{
158
    SIZE_T i;
159
160
    if( cbBytes == 16 )
161
    {
162
        PCUINT32 s1 = (PCUINT32) pbSrc1;
163
        PCUINT32 s2 = (PCUINT32) pbSrc2;
164
        PUINT32 d = (PUINT32) pbResult;
165
166
        d[0] = s1[0] ^ s2[0];
167
        d[1] = s1[1] ^ s2[1];
168
        d[2] = s1[2] ^ s2[2];
169
        d[3] = s1[3] ^ s2[3];
170
    }
171
    else
172
    {
173
        i = 0;
174
        while( i + 3 < cbBytes )
175
        {
176
            *(UINT32 *)&pbResult[i] = *(UINT32 *)&pbSrc1[i] ^ *(UINT32 *)&pbSrc2[i];
177
            i += 4;
178
        }
179
180
        while( i < cbBytes )
181
        {
182
            pbResult[i] = pbSrc1[i] ^ pbSrc2[i];
183
            i++;
184
        }
185
    }
186
}
187
188
#elif SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64
189
190
VOID
191
SYMCRYPT_CALL
192
SymCryptXorBytes(
193
    _In_reads_( cbBytes )   PCBYTE  pbSrc1,
194
    _In_reads_( cbBytes )   PCBYTE  pbSrc2,
195
    _Out_writes_( cbBytes ) PBYTE   pbResult,
196
                            SIZE_T  cbBytes )
197
149k
{
198
149k
    if( cbBytes == 16 )
199
143k
    {
200
143k
        PCUINT64 s1 = (PCUINT64) pbSrc1;
201
143k
        PCUINT64 s2 = (PCUINT64) pbSrc2;
202
143k
        PUINT64  d = (PUINT64) pbResult;
203
204
143k
        d[0] = s1[0] ^ s2[0];
205
143k
        d[1] = s1[1] ^ s2[1];
206
143k
    }
207
5.61k
    else
208
5.61k
    {
209
27.3k
        while( cbBytes >= 8 )
210
21.7k
        {
211
21.7k
            *(UINT64 *)pbResult = *(UINT64 *)pbSrc1 ^ *(UINT64 *)pbSrc2;
212
21.7k
            pbSrc1 += 8;
213
21.7k
            pbSrc2 += 8;
214
21.7k
            pbResult += 8;
215
21.7k
            cbBytes -= 8;
216
21.7k
        }
217
218
16.8k
        while( cbBytes > 0 )
219
11.2k
        {
220
11.2k
            *pbResult = *pbSrc1 ^ *pbSrc2;
221
11.2k
            pbResult++;
222
11.2k
            pbSrc1++;
223
11.2k
            pbSrc2++;
224
11.2k
            cbBytes--;
225
11.2k
        }
226
5.61k
    }
227
149k
}
228
229
230
#else
231
//
232
// Generic code
233
//
234
VOID
235
SYMCRYPT_CALL
236
SymCryptXorBytes(
237
    _In_reads_( cbBytes )   PCBYTE  pbSrc1,
238
    _In_reads_( cbBytes )   PCBYTE  pbSrc2,
239
    _Out_writes_( cbBytes ) PBYTE   pbResult,
240
                            SIZE_T  cbBytes )
241
{
242
    SIZE_T i;
243
244
    for( i=0; i<cbBytes; i++ )
245
    {
246
        pbResult[i] = pbSrc1[i] ^ pbSrc2[i];
247
    }
248
}
249
#endif
250
251
252
//
253
// Generic LSB/MSBfirst load/store code for variable-sized buffers.
254
// These implementations are inefficient and not side-channel safe.
255
// This is sufficient for the current usage (typically to allow
256
// callers to read/write RSA public exponents from/to variable-sized
257
// buffers).
258
// Consider upgrading them in future.
259
//
260
261
UINT32
262
SymCryptUint32Bitsize( UINT32 value )
263
//
264
// Some CPUs/compilers have intrinsics for this,
265
// but this is portable and works everywhere.
266
//
267
0
{
268
0
    UINT32 res;
269
270
0
    res = 0;
271
0
    while( value != 0 )
272
0
    {
273
0
        res += 1;
274
0
        value >>= 1;
275
0
    }
276
277
0
    return res;
278
0
}
279
280
UINT32
281
SymCryptUint64Bitsize( UINT64 value )
282
0
{
283
0
    UINT32 res;
284
0
    UINT32 upper;
285
286
0
    upper = (UINT32)(value >> 32);
287
288
0
    if( upper == 0 )
289
0
    {
290
0
        res = SymCryptUint32Bitsize( (UINT32) value );
291
0
    } else {
292
0
        res = 32 + SymCryptUint32Bitsize( upper );
293
0
    }
294
295
0
    return res;
296
0
}
297
298
UINT32
299
SymCryptUint32Bytesize( UINT32 value )
300
0
{
301
0
    if( value == 0 )
302
0
    {
303
0
        return 0;
304
0
    }
305
0
    if( value < 0x100 )
306
0
    {
307
0
        return 1;
308
0
    }
309
0
    if( value < 0x10000 )
310
0
    {
311
0
        return 2;
312
0
    }
313
0
    if( value < 0x1000000 )
314
0
    {
315
0
        return 3;
316
0
    }
317
0
    return 4;
318
0
}
319
320
UINT32
321
SymCryptUint64Bytesize( UINT64 value )
322
0
{
323
0
    UINT32 res;
324
0
    UINT32 upper;
325
326
0
    upper = (UINT32)(value >> 32);
327
328
0
    if( upper == 0 )
329
0
    {
330
0
        res = SymCryptUint32Bytesize( (UINT32) value );
331
0
    } else {
332
0
        res = 4 + SymCryptUint32Bytesize( upper );
333
0
    }
334
335
0
    return res;
336
0
}
337
338
339
SYMCRYPT_ERROR
340
SYMCRYPT_CALL
341
SymCryptLoadLsbFirstUint32(
342
    _In_reads_( cbSrc ) PCBYTE  pbSrc,
343
                        SIZE_T  cbSrc,
344
    _Out_               PUINT32 pDst )
345
0
{
346
0
    UINT64 v64;
347
0
    UINT32 v32;
348
0
    SYMCRYPT_ERROR scError;
349
350
0
    scError = SymCryptLoadLsbFirstUint64( pbSrc, cbSrc, &v64 );
351
0
    if( scError != SYMCRYPT_NO_ERROR )
352
0
    {
353
0
        goto cleanup;
354
0
    }
355
356
0
    v32 = (UINT32) v64;
357
0
    if( v32 != v64 )
358
0
    {
359
0
        scError = SYMCRYPT_VALUE_TOO_LARGE;
360
0
        goto cleanup;
361
0
    }
362
363
0
    *pDst = v32;
364
365
0
cleanup:
366
0
    return scError;
367
0
}
368
369
SYMCRYPT_ERROR
370
SYMCRYPT_CALL
371
SymCryptLoadLsbFirstUint64(
372
    _In_reads_( cbSrc ) PCBYTE  pbSrc,
373
                        SIZE_T  cbSrc,
374
    _Out_               PUINT64 pDst )
375
0
{
376
0
    UINT64 v;
377
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
378
379
0
    v = 0;
380
0
    pbSrc += cbSrc;
381
0
    while( cbSrc > 8 )
382
0
    {
383
0
        if( *--pbSrc != 0 )
384
0
        {
385
0
            scError = SYMCRYPT_VALUE_TOO_LARGE;
386
0
            goto cleanup;
387
0
        }
388
0
        cbSrc--;
389
0
    }
390
391
0
    while( cbSrc > 0 )
392
0
    {
393
0
        v = (v << 8) | *--pbSrc;
394
0
        cbSrc--;
395
0
    }
396
397
0
    *pDst = v;
398
399
0
cleanup:
400
0
    return scError;
401
0
}
402
403
SYMCRYPT_ERROR
404
SYMCRYPT_CALL
405
SymCryptLoadMsbFirstUint32(
406
    _In_reads_( cbSrc ) PCBYTE  pbSrc,
407
                        SIZE_T  cbSrc,
408
    _Out_               PUINT32 pDst )
409
0
{
410
0
    UINT64 v64;
411
0
    UINT32 v32;
412
0
    SYMCRYPT_ERROR scError;
413
414
0
    scError = SymCryptLoadMsbFirstUint64( pbSrc, cbSrc, &v64 );
415
0
    if( scError != SYMCRYPT_NO_ERROR )
416
0
    {
417
0
        goto cleanup;
418
0
    }
419
420
0
    v32 = (UINT32) v64;
421
0
    if( v32 != v64 )
422
0
    {
423
0
        scError = SYMCRYPT_VALUE_TOO_LARGE;
424
0
        goto cleanup;
425
0
    }
426
427
0
    *pDst = v32;
428
429
0
cleanup:
430
0
    return scError;
431
0
}
432
433
434
SYMCRYPT_ERROR
435
SYMCRYPT_CALL
436
SymCryptLoadMsbFirstUint64(
437
    _In_reads_( cbSrc ) PCBYTE  pbSrc,
438
                        SIZE_T  cbSrc,
439
    _Out_               PUINT64 pDst )
440
0
{
441
0
    UINT64 v;
442
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
443
444
0
    v = 0;
445
0
    while( cbSrc > 8 )
446
0
    {
447
0
        if( *pbSrc++ != 0 )
448
0
        {
449
0
            scError = SYMCRYPT_VALUE_TOO_LARGE;
450
0
            goto cleanup;
451
0
        }
452
0
        cbSrc--;
453
0
    }
454
455
0
    while( cbSrc > 0 )
456
0
    {
457
0
        v = (v << 8) | *pbSrc++;
458
0
        cbSrc--;
459
0
    }
460
461
0
    *pDst = v;
462
463
0
cleanup:
464
0
    return scError;
465
0
}
466
467
468
SYMCRYPT_ERROR
469
SYMCRYPT_CALL
470
SymCryptStoreLsbFirstUint32(
471
                            UINT32  src,
472
    _Out_writes_( cbDst )   PBYTE   pbDst,
473
                            SIZE_T  cbDst )
474
0
{
475
0
    return SymCryptStoreLsbFirstUint64( src, pbDst, cbDst );
476
0
}
477
478
SYMCRYPT_ERROR
479
SYMCRYPT_CALL
480
SymCryptStoreLsbFirstUint64(
481
                            UINT64  src,
482
    _Out_writes_( cbDst )   PBYTE   pbDst,
483
                            SIZE_T  cbDst )
484
0
{
485
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
486
487
0
    while( cbDst > 0 )
488
0
    {
489
0
        *pbDst++ = (BYTE) src;
490
0
        src >>= 8;
491
0
        cbDst--;
492
0
    }
493
494
0
    if( src != 0 )
495
0
    {
496
0
        scError = SYMCRYPT_VALUE_TOO_LARGE;
497
0
        goto cleanup;
498
0
    }
499
500
0
cleanup:
501
0
    return scError;
502
0
}
503
504
SYMCRYPT_ERROR
505
SYMCRYPT_CALL
506
SymCryptStoreMsbFirstUint32(
507
                            UINT32  src,
508
    _Out_writes_( cbDst )   PBYTE   pbDst,
509
                            SIZE_T  cbDst )
510
0
{
511
0
    return SymCryptStoreMsbFirstUint64( src, pbDst, cbDst );
512
0
}
513
514
SYMCRYPT_ERROR
515
SYMCRYPT_CALL
516
SymCryptStoreMsbFirstUint64(
517
                            UINT64  src,
518
    _Out_writes_( cbDst )   PBYTE   pbDst,
519
                            SIZE_T  cbDst )
520
0
{
521
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
522
523
0
    pbDst += cbDst;
524
0
    while( cbDst > 0 )
525
0
    {
526
0
        *--pbDst = (BYTE) src;
527
0
        src >>= 8;
528
0
        cbDst--;
529
0
    }
530
531
0
    if( src != 0 )
532
0
    {
533
0
        scError = SYMCRYPT_VALUE_TOO_LARGE;
534
0
        goto cleanup;
535
0
    }
536
537
0
cleanup:
538
0
    return scError;
539
0
}
540
541
542
543
544