Line data Source code
1 : #if FD_HAS_OPENSSL
2 : #include "../../util/bits/fd_bits.h"
3 : #include "fd_openssl_tile.h"
4 :
5 : #include <dirent.h>
6 : #include <unistd.h>
7 : #include <errno.h>
8 :
9 : /* Thread-local alloc object for each tile that uses OpenSSL. */
10 : FD_TL fd_alloc_t * fd_ossl_alloc = NULL;
11 : FD_TL ulong fd_ossl_alloc_errors = 0UL;
12 :
13 : /* OpenSSL tries to read files and allocate memory and other dumb things
14 : on a thread local basis, so we need a special initializer process to
15 : make OpenSSL use our custom allocators before seccomp kicks in.
16 :
17 : OpenSSL allows us to specify custom memory allocation functions,
18 : which we want to point to an fd_alloc_t, but it does not let us use a
19 : context object. Instead we stash it in this thread local, which is
20 : OK because the parent workspace exists for the duration of the SSL
21 : context, and the process only has one thread.
22 :
23 : Currently fd_alloc doesn't support realloc, so it's implemented on
24 : top of malloc and free, and then also it doesn't support getting the
25 : size of an allocation from the pointer, which we need for realloc, so
26 : we pad each alloc by 8 bytes and stuff the size into the first 8
27 : bytes. */
28 :
29 : static void *
30 : crypto_malloc( ulong num,
31 : char const * file,
32 0 : int line ) {
33 0 : (void)file;
34 0 : (void)line;
35 0 : void * result = fd_alloc_malloc( fd_ossl_alloc, 8UL, num + 8UL );
36 0 : if( FD_UNLIKELY( !result ) ) {
37 0 : fd_ossl_alloc_errors++;
38 0 : return NULL;
39 0 : }
40 0 : *(ulong*)result = num;
41 0 : return (uchar*)result + 8UL;
42 0 : }
43 :
44 : static void
45 : crypto_free( void * addr,
46 : char const * file,
47 0 : int line ) {
48 0 : (void)file;
49 0 : (void)line;
50 :
51 0 : if( FD_UNLIKELY( !addr ) ) return;
52 0 : fd_alloc_free( fd_ossl_alloc, (uchar*)addr - 8UL );
53 0 : }
54 :
55 : static void *
56 : crypto_realloc( void * addr,
57 : ulong num,
58 : char const * file,
59 0 : int line ) {
60 0 : (void)file;
61 0 : (void)line;
62 :
63 0 : if( FD_UNLIKELY( !addr ) ) return crypto_malloc( num, file, line );
64 0 : if( FD_UNLIKELY( !num ) ) {
65 0 : crypto_free( addr, file, line );
66 0 : return NULL;
67 0 : }
68 :
69 0 : void * new = fd_alloc_malloc( fd_ossl_alloc, 8UL, num + 8UL );
70 0 : if( FD_UNLIKELY( !new ) ) return NULL;
71 :
72 0 : ulong old_num = *(ulong*)( (uchar*)addr - 8UL );
73 0 : fd_memcpy( (uchar*)new + 8, (uchar*)addr, fd_ulong_min( old_num, num ) );
74 0 : fd_alloc_free( fd_ossl_alloc, (uchar*)addr - 8UL );
75 0 : *(ulong*)new = num;
76 0 : return (uchar*)new + 8UL;
77 0 : }
78 :
79 : void
80 0 : fd_ossl_tile_init( fd_alloc_t * alloc ) {
81 : /* OpenSSL's CRYPTO_set_mem_functions is a global operation so it can
82 : only be called once for all threads/processes. */
83 0 : FD_ONCE_BEGIN {
84 0 : if( FD_UNLIKELY( !CRYPTO_set_mem_functions( crypto_malloc, crypto_realloc, crypto_free ) ) ) {
85 0 : FD_LOG_ERR(( "CRYPTO_set_mem_functions failed" ));
86 0 : }
87 0 : } FD_ONCE_END;
88 :
89 0 : FD_TEST( alloc );
90 0 : fd_ossl_alloc = alloc;
91 :
92 0 : FD_ONCE_BEGIN {
93 0 : OPENSSL_init_ssl(
94 0 : OPENSSL_INIT_LOAD_SSL_STRINGS |
95 0 : OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
96 0 : OPENSSL_INIT_NO_LOAD_CONFIG,
97 0 : NULL );
98 0 : } FD_ONCE_END;
99 0 : }
100 :
101 : void
102 0 : fd_ossl_load_certs( SSL_CTX * ssl_ctx ) {
103 0 : X509_STORE * ca_certs = X509_STORE_new();
104 0 : if( FD_UNLIKELY( !ca_certs ) ) {
105 0 : FD_LOG_ERR(( "X509_STORE_new failed" ));
106 0 : }
107 :
108 0 : static char const default_dir[] = "/etc/ssl/certs/";
109 0 : DIR * dir = opendir( default_dir );
110 0 : if( FD_UNLIKELY( !dir ) ) {
111 0 : FD_LOG_ERR(( "opendir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
112 0 : }
113 :
114 0 : struct dirent * entry;
115 0 : errno = 0; // clear old value since entry can be NULL when reaching end of directory.
116 0 : while( (entry = readdir( dir )) ) {
117 0 : if( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) continue;
118 :
119 0 : char cert_path[ PATH_MAX ];
120 0 : char * p = fd_cstr_init( cert_path );
121 0 : p = fd_cstr_append_text( p, default_dir, sizeof(default_dir)-1 );
122 0 : p = fd_cstr_append_cstr_safe( p, entry->d_name, (ulong)(cert_path+sizeof(cert_path)-1) - (ulong)p );
123 0 : fd_cstr_fini( p );
124 :
125 0 : if( !X509_STORE_load_locations( ca_certs, cert_path, NULL ) ) {
126 : /* Not all files in /etc/ssl/certs are valid certs, so ignore errors */
127 0 : continue;
128 0 : }
129 0 : errno = 0;
130 0 : }
131 :
132 0 : if( FD_UNLIKELY( errno && errno!=ENOENT ) ) {
133 0 : FD_LOG_ERR(( "readdir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
134 0 : }
135 :
136 0 : STACK_OF(X509) * cert_list = X509_STORE_get1_all_certs( ca_certs );
137 0 : FD_LOG_INFO(( "Loaded %d CA certs from %s into OpenSSL", sk_X509_num( cert_list ), default_dir ));
138 0 : if( fd_log_level_logfile()==0 ) {
139 0 : for( int i=0; i<sk_X509_num( cert_list ); i++ ) {
140 0 : X509 * cert = sk_X509_value( cert_list, i );
141 0 : FD_LOG_DEBUG(( "Loaded CA cert \"%s\"", X509_NAME_oneline( X509_get_subject_name( cert ), NULL, 0 ) ));
142 0 : }
143 0 : }
144 0 : sk_X509_pop_free( cert_list, X509_free );
145 :
146 0 : SSL_CTX_set_cert_store( ssl_ctx, ca_certs );
147 :
148 0 : if( FD_UNLIKELY( 0!=closedir( dir ) ) ) {
149 0 : FD_LOG_ERR(( "closedir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
150 0 : }
151 :
152 0 : SSL_CTX_set_verify( ssl_ctx, SSL_VERIFY_PEER, NULL );
153 0 : }
154 :
155 : #endif /* FD_HAS_OPENSSL */
|