Coverage Report

Created: 2024-08-27 12:20

/src/openssl/crypto/cryptlib.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 1998-2018 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 */
10
11
#include "e_os.h"
12
#include "crypto/cryptlib.h"
13
#include <openssl/safestack.h>
14
15
#if     defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
16
        defined(__x86_64) || defined(__x86_64__) || \
17
        defined(_M_AMD64) || defined(_M_X64)
18
19
extern unsigned int OPENSSL_ia32cap_P[4];
20
21
# if defined(OPENSSL_CPUID_OBJ)
22
23
/*
24
 * Purpose of these minimalistic and character-type-agnostic subroutines
25
 * is to break dependency on MSVCRT (on Windows) and locale. This makes
26
 * OPENSSL_cpuid_setup safe to use as "constructor". "Character-type-
27
 * agnostic" means that they work with either wide or 8-bit characters,
28
 * exploiting the fact that first 127 characters can be simply casted
29
 * between the sets, while the rest would be simply rejected by ossl_is*
30
 * subroutines.
31
 */
32
#  ifdef _WIN32
33
typedef WCHAR variant_char;
34
35
static variant_char *ossl_getenv(const char *name)
36
{
37
    /*
38
     * Since we pull only one environment variable, it's simpler to
39
     * to just ignore |name| and use equivalent wide-char L-literal.
40
     * As well as to ignore excessively long values...
41
     */
42
    static WCHAR value[48];
43
    DWORD len = GetEnvironmentVariableW(L"OPENSSL_ia32cap", value, 48);
44
45
    return (len > 0 && len < 48) ? value : NULL;
46
}
47
#  else
48
typedef char variant_char;
49
1.11k
#   define ossl_getenv getenv
50
#  endif
51
52
#  include "crypto/ctype.h"
53
54
static int todigit(variant_char c)
55
0
{
56
0
    if (ossl_isdigit(c))
57
0
        return c - '0';
58
0
    else if (ossl_isxdigit(c))
59
0
        return ossl_tolower(c) - 'a' + 10;
60
61
    /* return largest base value to make caller terminate the loop */
62
0
    return 16;
63
0
}
64
65
static uint64_t ossl_strtouint64(const variant_char *str)
66
0
{
67
0
    uint64_t ret = 0;
68
0
    unsigned int digit, base = 10;
69
70
0
    if (*str == '0') {
71
0
        base = 8, str++;
72
0
        if (ossl_tolower(*str) == 'x')
73
0
            base = 16, str++;
74
0
    }
75
76
0
    while((digit = todigit(*str++)) < base)
77
0
        ret = ret * base + digit;
78
79
0
    return ret;
80
0
}
81
82
static variant_char *ossl_strchr(const variant_char *str, char srch)
83
0
{   variant_char c;
84
85
0
    while((c = *str)) {
86
0
        if (c == srch)
87
0
            return (variant_char *)str;
88
0
        str++;
89
0
    }
90
91
0
    return NULL;
92
0
}
93
94
#  define OPENSSL_CPUID_SETUP
95
typedef uint64_t IA32CAP;
96
97
void OPENSSL_cpuid_setup(void)
98
2.22k
{
99
2.22k
    static int trigger = 0;
100
2.22k
    IA32CAP OPENSSL_ia32_cpuid(unsigned int *);
101
2.22k
    IA32CAP vec;
102
2.22k
    const variant_char *env;
103
104
2.22k
    if (trigger)
105
1.11k
        return;
106
107
1.11k
    trigger = 1;
108
1.11k
    if ((env = ossl_getenv("OPENSSL_ia32cap")) != NULL) {
109
0
        int off = (env[0] == '~') ? 1 : 0;
110
111
0
        vec = ossl_strtouint64(env + off);
112
113
0
        if (off) {
114
0
            IA32CAP mask = vec;
115
0
            vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P) & ~mask;
116
0
            if (mask & (1<<24)) {
117
                /*
118
                 * User disables FXSR bit, mask even other capabilities
119
                 * that operate exclusively on XMM, so we don't have to
120
                 * double-check all the time. We mask PCLMULQDQ, AMD XOP,
121
                 * AES-NI and AVX. Formally speaking we don't have to
122
                 * do it in x86_64 case, but we can safely assume that
123
                 * x86_64 users won't actually flip this flag.
124
                 */
125
0
                vec &= ~((IA32CAP)(1<<1|1<<11|1<<25|1<<28) << 32);
126
0
            }
127
0
        } else if (env[0] == ':') {
128
0
            vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
129
0
        }
130
131
0
        if ((env = ossl_strchr(env, ':')) != NULL) {
132
0
            IA32CAP vecx;
133
134
0
            env++;
135
0
            off = (env[0] == '~') ? 1 : 0;
136
0
            vecx = ossl_strtouint64(env + off);
137
0
            if (off) {
138
0
                OPENSSL_ia32cap_P[2] &= ~(unsigned int)vecx;
139
0
                OPENSSL_ia32cap_P[3] &= ~(unsigned int)(vecx >> 32);
140
0
            } else {
141
0
                OPENSSL_ia32cap_P[2] = (unsigned int)vecx;
142
0
                OPENSSL_ia32cap_P[3] = (unsigned int)(vecx >> 32);
143
0
            }
144
0
        } else {
145
0
            OPENSSL_ia32cap_P[2] = 0;
146
0
            OPENSSL_ia32cap_P[3] = 0;
147
0
        }
148
1.11k
    } else {
149
1.11k
        vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
150
1.11k
    }
151
152
    /*
153
     * |(1<<10) sets a reserved bit to signal that variable
154
     * was initialized already... This is to avoid interference
155
     * with cpuid snippets in ELF .init segment.
156
     */
157
1.11k
    OPENSSL_ia32cap_P[0] = (unsigned int)vec | (1 << 10);
158
1.11k
    OPENSSL_ia32cap_P[1] = (unsigned int)(vec >> 32);
159
1.11k
}
160
# else
161
unsigned int OPENSSL_ia32cap_P[4];
162
# endif
163
#endif
164
#if !defined(OPENSSL_CPUID_SETUP) && !defined(OPENSSL_CPUID_OBJ)
165
void OPENSSL_cpuid_setup(void)
166
{
167
}
168
#endif
169
170
#if defined(_WIN32)
171
# include <tchar.h>
172
# include <signal.h>
173
# ifdef __WATCOMC__
174
#  if defined(_UNICODE) || defined(__UNICODE__)
175
#   define _vsntprintf _vsnwprintf
176
#  else
177
#   define _vsntprintf _vsnprintf
178
#  endif
179
# endif
180
# ifdef _MSC_VER
181
#  define alloca _alloca
182
# endif
183
184
# if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
185
#  ifdef OPENSSL_SYS_WIN_CORE
186
187
int OPENSSL_isservice(void)
188
{
189
    /* OneCore API cannot interact with GUI */
190
    return 1;
191
}
192
#  else
193
int OPENSSL_isservice(void)
194
{
195
    HWINSTA h;
196
    DWORD len;
197
    WCHAR *name;
198
    static union {
199
        void *p;
200
        FARPROC f;
201
    } _OPENSSL_isservice = {
202
        NULL
203
    };
204
205
    if (_OPENSSL_isservice.p == NULL) {
206
        HANDLE mod = GetModuleHandle(NULL);
207
        FARPROC f = NULL;
208
209
        if (mod != NULL)
210
            f = GetProcAddress(mod, "_OPENSSL_isservice");
211
        if (f == NULL)
212
            _OPENSSL_isservice.p = (void *)-1;
213
        else
214
            _OPENSSL_isservice.f = f;
215
    }
216
217
    if (_OPENSSL_isservice.p != (void *)-1)
218
        return (*_OPENSSL_isservice.f) ();
219
220
    h = GetProcessWindowStation();
221
    if (h == NULL)
222
        return -1;
223
224
    if (GetUserObjectInformationW(h, UOI_NAME, NULL, 0, &len) ||
225
        GetLastError() != ERROR_INSUFFICIENT_BUFFER)
226
        return -1;
227
228
    if (len > 512)
229
        return -1;              /* paranoia */
230
    len++, len &= ~1;           /* paranoia */
231
    name = (WCHAR *)alloca(len + sizeof(WCHAR));
232
    if (!GetUserObjectInformationW(h, UOI_NAME, name, len, &len))
233
        return -1;
234
235
    len++, len &= ~1;           /* paranoia */
236
    name[len / sizeof(WCHAR)] = L'\0'; /* paranoia */
237
#   if 1
238
    /*
239
     * This doesn't cover "interactive" services [working with real
240
     * WinSta0's] nor programs started non-interactively by Task Scheduler
241
     * [those are working with SAWinSta].
242
     */
243
    if (wcsstr(name, L"Service-0x"))
244
        return 1;
245
#   else
246
    /* This covers all non-interactive programs such as services. */
247
    if (!wcsstr(name, L"WinSta0"))
248
        return 1;
249
#   endif
250
    else
251
        return 0;
252
}
253
#  endif
254
# else
255
int OPENSSL_isservice(void)
256
{
257
    return 0;
258
}
259
# endif
260
261
void OPENSSL_showfatal(const char *fmta, ...)
262
{
263
    va_list ap;
264
    TCHAR buf[256];
265
    const TCHAR *fmt;
266
    /*
267
     * First check if it's a console application, in which case the
268
     * error message would be printed to standard error.
269
     * Windows CE does not have a concept of a console application,
270
     * so we need to guard the check.
271
     */
272
# ifdef STD_ERROR_HANDLE
273
    HANDLE h;
274
275
    if ((h = GetStdHandle(STD_ERROR_HANDLE)) != NULL &&
276
        GetFileType(h) != FILE_TYPE_UNKNOWN) {
277
        /* must be console application */
278
        int len;
279
        DWORD out;
280
281
        va_start(ap, fmta);
282
        len = _vsnprintf((char *)buf, sizeof(buf), fmta, ap);
283
        WriteFile(h, buf, len < 0 ? sizeof(buf) : (DWORD) len, &out, NULL);
284
        va_end(ap);
285
        return;
286
    }
287
# endif
288
289
    if (sizeof(TCHAR) == sizeof(char))
290
        fmt = (const TCHAR *)fmta;
291
    else
292
        do {
293
            int keepgoing;
294
            size_t len_0 = strlen(fmta) + 1, i;
295
            WCHAR *fmtw;
296
297
            fmtw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
298
            if (fmtw == NULL) {
299
                fmt = (const TCHAR *)L"no stack?";
300
                break;
301
            }
302
            if (!MultiByteToWideChar(CP_ACP, 0, fmta, len_0, fmtw, len_0))
303
                for (i = 0; i < len_0; i++)
304
                    fmtw[i] = (WCHAR)fmta[i];
305
            for (i = 0; i < len_0; i++) {
306
                if (fmtw[i] == L'%')
307
                    do {
308
                        keepgoing = 0;
309
                        switch (fmtw[i + 1]) {
310
                        case L'0':
311
                        case L'1':
312
                        case L'2':
313
                        case L'3':
314
                        case L'4':
315
                        case L'5':
316
                        case L'6':
317
                        case L'7':
318
                        case L'8':
319
                        case L'9':
320
                        case L'.':
321
                        case L'*':
322
                        case L'-':
323
                            i++;
324
                            keepgoing = 1;
325
                            break;
326
                        case L's':
327
                            fmtw[i + 1] = L'S';
328
                            break;
329
                        case L'S':
330
                            fmtw[i + 1] = L's';
331
                            break;
332
                        case L'c':
333
                            fmtw[i + 1] = L'C';
334
                            break;
335
                        case L'C':
336
                            fmtw[i + 1] = L'c';
337
                            break;
338
                        }
339
                    } while (keepgoing);
340
            }
341
            fmt = (const TCHAR *)fmtw;
342
        } while (0);
343
344
    va_start(ap, fmta);
345
    _vsntprintf(buf, OSSL_NELEM(buf) - 1, fmt, ap);
346
    buf[OSSL_NELEM(buf) - 1] = _T('\0');
347
    va_end(ap);
348
349
# if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333
350
#  ifdef OPENSSL_SYS_WIN_CORE
351
    /* ONECORE is always NONGUI and NT >= 0x0601 */
352
353
    /*
354
    * TODO: (For non GUI and no std error cases)
355
    * Add event logging feature here.
356
    */
357
358
#   if !defined(NDEBUG)
359
        /*
360
        * We are in a situation where we tried to report a critical
361
        * error and this failed for some reason. As a last resort,
362
        * in debug builds, send output to the debugger or any other
363
        * tool like DebugView which can monitor the output.
364
        */
365
        OutputDebugString(buf);
366
#   endif
367
#  else
368
    /* this -------------v--- guards NT-specific calls */
369
    if (check_winnt() && OPENSSL_isservice() > 0) {
370
        HANDLE hEventLog = RegisterEventSource(NULL, _T("OpenSSL"));
371
372
        if (hEventLog != NULL) {
373
            const TCHAR *pmsg = buf;
374
375
            if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, 0, NULL,
376
                             1, 0, &pmsg, NULL)) {
377
#   if !defined(NDEBUG)
378
                /*
379
                 * We are in a situation where we tried to report a critical
380
                 * error and this failed for some reason. As a last resort,
381
                 * in debug builds, send output to the debugger or any other
382
                 * tool like DebugView which can monitor the output.
383
                 */
384
                OutputDebugString(pmsg);
385
#   endif
386
            }
387
388
            (void)DeregisterEventSource(hEventLog);
389
        }
390
    } else {
391
        MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
392
    }
393
#  endif
394
# else
395
    MessageBox(NULL, buf, _T("OpenSSL: FATAL"), MB_OK | MB_ICONERROR);
396
# endif
397
}
398
#else
399
void OPENSSL_showfatal(const char *fmta, ...)
400
0
{
401
0
#ifndef OPENSSL_NO_STDIO
402
0
    va_list ap;
403
404
0
    va_start(ap, fmta);
405
0
    vfprintf(stderr, fmta, ap);
406
0
    va_end(ap);
407
0
#endif
408
0
}
409
410
int OPENSSL_isservice(void)
411
0
{
412
0
    return 0;
413
0
}
414
#endif
415
416
void OPENSSL_die(const char *message, const char *file, int line)
417
0
{
418
0
    OPENSSL_showfatal("%s:%d: OpenSSL internal error: %s\n",
419
0
                      file, line, message);
420
0
#if !defined(_WIN32)
421
0
    abort();
422
#else
423
    /*
424
     * Win32 abort() customarily shows a dialog, but we just did that...
425
     */
426
# if !defined(_WIN32_WCE)
427
    raise(SIGABRT);
428
# endif
429
    _exit(3);
430
#endif
431
0
}
432
433
#if !defined(OPENSSL_CPUID_OBJ)
434
/*
435
 * The volatile is used to to ensure that the compiler generates code that reads
436
 * all values from the array and doesn't try to optimize this away. The standard
437
 * doesn't actually require this behavior if the original data pointed to is
438
 * not volatile, but compilers do this in practice anyway.
439
 *
440
 * There are also assembler versions of this function.
441
 */
442
# undef CRYPTO_memcmp
443
int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
444
{
445
    size_t i;
446
    const volatile unsigned char *a = in_a;
447
    const volatile unsigned char *b = in_b;
448
    unsigned char x = 0;
449
450
    for (i = 0; i < len; i++)
451
        x |= a[i] ^ b[i];
452
453
    return x;
454
}
455
456
/*
457
 * For systems that don't provide an instruction counter register or equivalent.
458
 */
459
uint32_t OPENSSL_rdtsc(void)
460
{
461
    return 0;
462
}
463
464
size_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
465
{
466
    return 0;
467
}
468
469
size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
470
{
471
    return 0;
472
}
473
#endif