aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/s2n/utils/s2n_init.c
blob: 8f1b66e0f94f0fa221f7854b158cdb70b9edf53e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
#include <pthread.h>

#include "crypto/s2n_fips.h"
#include "crypto/s2n_libcrypto.h"
#include "crypto/s2n_locking.h"
#include "error/s2n_errno.h"
#include "openssl/opensslv.h"
#include "pq-crypto/s2n_pq.h"
#include "tls/extensions/s2n_client_key_share.h"
#include "tls/extensions/s2n_extension_type.h"
#include "tls/s2n_cipher_suites.h"
#include "tls/s2n_security_policies.h"
#include "tls/s2n_tls13_secrets.h"
#include "utils/s2n_mem.h"
#include "utils/s2n_random.h"
#include "utils/s2n_safety.h"
#include "utils/s2n_safety_macros.h"

static void s2n_cleanup_atexit(void);

static pthread_t main_thread = 0;
static bool initialized = false;
static bool atexit_cleanup = true;
int s2n_disable_atexit(void)
{
    POSIX_ENSURE(!initialized, S2N_ERR_INITIALIZED);
    atexit_cleanup = false;
    return S2N_SUCCESS;
}

int s2n_enable_atexit(void)
{
    atexit_cleanup = true;
    return S2N_SUCCESS;
}

int s2n_init(void)
{
    /* USAGE-GUIDE says s2n_init MUST NOT be called more than once
     * Public documentation for API states s2n_init should only be called once
     * https://github.com/aws/s2n-tls/issues/3446 is a result of not enforcing this
     */
    POSIX_ENSURE(!initialized, S2N_ERR_INITIALIZED);

    main_thread = pthread_self();
    /* Should run before any init method that calls libcrypto methods
     * to ensure we don't try to call methods that don't exist.
     * It doesn't require any locks since it only deals with values that
     * should be constant, so can run before s2n_locking_init. */
    POSIX_GUARD_RESULT(s2n_libcrypto_validate_runtime());
    /* Must run before any init method that allocates memory. */
    POSIX_GUARD(s2n_mem_init());
    /* Must run before any init method that calls libcrypto methods. */
    POSIX_GUARD_RESULT(s2n_locking_init());
    POSIX_GUARD_RESULT(s2n_libcrypto_init());
    POSIX_GUARD(s2n_fips_init());
    POSIX_GUARD_RESULT(s2n_rand_init());
    POSIX_GUARD(s2n_cipher_suites_init());
    POSIX_GUARD(s2n_security_policies_init());
    POSIX_GUARD(s2n_config_defaults_init());
    POSIX_GUARD(s2n_extension_type_init());
    POSIX_GUARD_RESULT(s2n_pq_init());
    POSIX_GUARD_RESULT(s2n_tls13_empty_transcripts_init());

    if (atexit_cleanup) {
        POSIX_ENSURE_OK(atexit(s2n_cleanup_atexit), S2N_ERR_ATEXIT);
    }

    if (getenv("S2N_PRINT_STACKTRACE")) {
        s2n_stack_traces_enabled_set(true);
    }

    initialized = true;

    return S2N_SUCCESS;
}

static bool s2n_cleanup_atexit_impl(void)
{
    /* all of these should run, regardless of result, but the
     * values to need to be consumed to prevent warnings */

    /* the configs need to be wiped before resetting the memory callbacks */
    s2n_wipe_static_configs();

    bool cleaned_up = s2n_result_is_ok(s2n_cipher_suites_cleanup())
            && s2n_result_is_ok(s2n_rand_cleanup_thread())
            && s2n_result_is_ok(s2n_rand_cleanup())
            && s2n_result_is_ok(s2n_libcrypto_cleanup())
            && s2n_result_is_ok(s2n_locking_cleanup())
            && (s2n_mem_cleanup() == S2N_SUCCESS);

    initialized = !cleaned_up;
    return cleaned_up;
}

int s2n_cleanup(void)
{
    /* s2n_cleanup is supposed to be called from each thread before exiting,
     * so ensure that whatever clean ups we have here are thread safe */
    POSIX_GUARD_RESULT(s2n_rand_cleanup_thread());

    /* If this is the main thread and atexit cleanup is disabled,
     * perform final cleanup now */
    if (pthread_equal(pthread_self(), main_thread) && !atexit_cleanup) {
        /* some cleanups are not idempotent (rand_cleanup, mem_cleanup) so protect */
        POSIX_ENSURE(initialized, S2N_ERR_NOT_INITIALIZED);
        POSIX_ENSURE(s2n_cleanup_atexit_impl(), S2N_ERR_ATEXIT);
    }

    return 0;
}

static void s2n_cleanup_atexit(void)
{
    (void) s2n_cleanup_atexit_impl();
}