1 /****************************************************************************
2 * *
3 * cryptlib Core Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7
8 #include "crypt.h"
9
10 /* Prototypes for functions in init.c. These should actually be annotated
11 with CHECK_RETVAL_ACQUIRELOCK( MUTEX_LOCKNAME( initialisation ) and
12 RELEASELOCK( MUTEX_LOCKNAME( initialisation ) ) but the mutex locking
13 types aren't visible outside the kernel and in any case the annotation is
14 only required where the functions are defined, so we just annotate them
15 normally here */
16
17 CHECK_RETVAL \
18 int krnlBeginInit( void );
19 void krnlCompleteInit( void );
20 CHECK_RETVAL \
21 int krnlBeginShutdown( void );
22 RETVAL \
23 int krnlCompleteShutdown( void );
24
25 /* Temporary kludge for functions that have to be performed mid-startup or
26 mid-shutdown */
27
28 int destroyObjects( void );
29 CHECK_RETVAL \
30 int testKernel( void );
31
32 /* Some messages communicate standard data values that are used again and
33 again so we predefine values for these that can be used globally */
34
35 const int messageValueTrue = TRUE;
36 const int messageValueFalse = FALSE;
37 const int messageValueCryptOK = CRYPT_OK;
38 const int messageValueCryptError = CRYPT_ERROR;
39 const int messageValueCryptUnused = CRYPT_UNUSED;
40 const int messageValueCryptUseDefault = CRYPT_USE_DEFAULT;
41 const int messageValueCursorFirst = CRYPT_CURSOR_FIRST;
42 const int messageValueCursorNext = CRYPT_CURSOR_NEXT;
43 const int messageValueCursorPrevious = CRYPT_CURSOR_PREVIOUS;
44 const int messageValueCursorLast = CRYPT_CURSOR_LAST;
45
46 /* OS X Snow Leopard broke dlopen(), if it's called from a (sub-)thread then
47 it dies with a SIGTRAP. Specifically, if you dlopen() a shared library
48 linked with CoreFoundation from a thread and the calling app wasn't
49 linked with CoreFoundation then the function CFInitialize() inside
50 dlopen() checks if the thread is the main thread (specifically
51 CFInitialize is declared with __attribute__ ((constructor))) and if it
52 isn't being called from the main thread it crashes with a SIGTRAP. The
53 inability to call dlopen() from a thread was apparently a requirement in
54 pre-Snow Leopard versions as well but was never enforced. One possible
55 workaround for this would be to require that any application that uses
56 cryptlib also link in CoreFoundation, but this will be rather error-
57 prone, so we disable asynchronous driver binding instead */
58
59 #if defined( __APPLE__ )
60 #undef USE_THREADS
61 #endif /* __APPLE__ */
62
63 /* If we're fuzzing we also disable threaded init in order to make the
64 startup behaviour deterministic */
65
66 #if defined( CONFIG_FUZZ )
67 #undef USE_THREADS
68 #endif /* CONFIG_FUZZ */
69
70 /****************************************************************************
71 * *
72 * Startup/Shutdown Routines *
73 * *
74 ****************************************************************************/
75
76 /* The initialisation and shutdown actions performed for various object
77 types. The pre-init actions are used to handle various preparatory
78 actions that are required before the actual init can be performed, for
79 example to create the system device and user object, which are needed by
80 the init routines. The pre-shutdown actions are used to signal to various
81 subsystems that a shutdown is about to occur, for example to allow the
82 networking subsystem to gracefully exit from any currently occurring
83 network I/O.
84
85 The certificate init is somewhat special in that it only performs an
86 internal consistency check rather than performing any actual
87 initialisation. As such it's not performed as part of the asynchronous
88 init since it has the potential to abort the cryptlib startup and as
89 such can't be allowed to come back at a later date an retroactively shut
90 things down after other crypto operations have already occurred. In fact
91 since it's part of the startup self-test it's done in the pre-init, as a
92 failure to complete the self-test will result in an immediate abort of the
93 init process.
94
95 The order of the init/shutdown actions is:
96
97 Object type Action
98 ----------- ------
99 Pre-init: Cert Self-test only
100 Device Create system object
101
102 Init: User Create default user object
103 Keyset Drivers - keysets | Done async.
104 Device Drivers - devices | if
105 Session Drivers - networking | available
106 [Several] Kernel self-test
107
108 Pre-shutdown: Session Networking - signal socket close
109 Device System object - signal entropy poll end
110
111 Shutdown: User Destroy default user object | Done by
112 Device Destroy system object | kernel
113 Keyset Drivers - keysets
114 Device Drivers - devices
115 Session Drivers - networking
116
117 The init order is determined by the following object dependencies:
118
119 All -> Device
120 (System object handles many message types).
121 User -> Keyset, Cert
122 (Default user object reads config data from the default keyset
123 to init drivers for keysets, devices, and networking, and
124 trusted certs. The default keyset isn't read via a loadable
125 keyset driver so it doesn't require the keyset driver init).
126 Self-test -> Several
127 (Kernel self-test creates several ephemeral objects in order to
128 test the kernel mechanisms).
129
130 The shutdown order is determined by the following dependencies:
131
132 Session (Networking needs to shut down to release any objects that are
133 blocked waiting on network I/O)
134 Device (System object needs to shut down ongoing entropy poll)
135
136 After this the shutdown proper can take place. The shutdown order is
137 noncritical, provided that the pre-shutdown actions have occurred.
138
139 In theory the user and system objects are destroyed as part of the
140 standard shutdown, however the kernel prevents these objects from ever
141 being explicitly destroyed so they're destroyed implicitly by the
142 destroyObjects() cleanup call */
143
144 CHECK_RETVAL \
145 int certManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
146 const MANAGEMENT_ACTION_TYPE action );
147 CHECK_RETVAL \
148 int deviceManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
149 const MANAGEMENT_ACTION_TYPE action );
150 CHECK_RETVAL \
151 int keysetManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
152 const MANAGEMENT_ACTION_TYPE action );
153 CHECK_RETVAL \
154 int sessionManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
155 const MANAGEMENT_ACTION_TYPE action );
156 CHECK_RETVAL \
157 int userManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
158 const MANAGEMENT_ACTION_TYPE action );
159
160 typedef CHECK_RETVAL \
161 int ( *MANAGEMENT_FUNCTION )( IN_ENUM( MANAGEMENT_ACTION ) \
162 const MANAGEMENT_ACTION_TYPE action );
163
164 static const MANAGEMENT_FUNCTION preInitFunctions[] = {
165 #ifdef USE_CERTIFICATES
166 certManagementFunction,
167 #endif /* USE_CERTIFICATES */
168 deviceManagementFunction,
169 NULL, NULL
170 };
171 static const MANAGEMENT_FUNCTION initFunctions[] = {
172 userManagementFunction,
173 NULL, NULL
174 };
175 static const MANAGEMENT_FUNCTION asyncInitFunctions[] = {
176 #ifdef USE_KEYSETS
177 keysetManagementFunction,
178 #endif /* USE_KEYSETS */
179 deviceManagementFunction,
180 #ifdef USE_SESSIONS
181 sessionManagementFunction,
182 #endif /* USE_SESSIONS */
183 NULL, NULL
184 };
185 static const MANAGEMENT_FUNCTION preShutdownFunctions[] = {
186 #ifdef USE_SESSIONS
187 sessionManagementFunction,
188 #endif /* USE_SESSIONS */
189 deviceManagementFunction,
190 NULL, NULL
191 };
192 static const MANAGEMENT_FUNCTION shutdownFunctions[] = {
193 /*userManagementFunction,*/ /*deviceManagementFunction,*/
194 #ifdef USE_KEYSETS
195 keysetManagementFunction,
196 #endif /* USE_KEYSETS */
197 deviceManagementFunction,
198 #ifdef USE_SESSIONS
199 sessionManagementFunction,
200 #endif /* USE_SESSIONS */
201 NULL, NULL
202 };
203
204 /* Dispatch a set of management actions */
205
206 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
dispatchManagementAction(IN_ARRAY (mgmtFunctionCount)const MANAGEMENT_FUNCTION * mgmtFunctions,IN_INT_SHORT const int mgmtFunctionCount,IN_ENUM (MANAGEMENT_ACTION)const MANAGEMENT_ACTION_TYPE action)207 static int dispatchManagementAction( IN_ARRAY( mgmtFunctionCount ) \
208 const MANAGEMENT_FUNCTION *mgmtFunctions,
209 IN_INT_SHORT const int mgmtFunctionCount,
210 IN_ENUM( MANAGEMENT_ACTION ) \
211 const MANAGEMENT_ACTION_TYPE action )
212 {
213 int i, status = CRYPT_OK;
214
215 assert( isReadPtr( mgmtFunctions, \
216 sizeof( MANAGEMENT_FUNCTION ) * mgmtFunctionCount ) );
217
218 REQUIRES( mgmtFunctionCount > 0 && \
219 mgmtFunctionCount < MAX_INTLENGTH_SHORT );
220 REQUIRES( action > MANAGEMENT_ACTION_NONE && \
221 action < MANAGEMENT_ACTION_LAST );
222
223 /* If we're performing a startup and the kernel is shutting down, bail
224 out now */
225 if( ( action == MANAGEMENT_ACTION_INIT ) && krnlIsExiting() )
226 return( CRYPT_ERROR_PERMISSION );
227
228 /* Dispatch each management action in turn */
229 for( i = 0; i < mgmtFunctionCount && \
230 mgmtFunctions[ i ] != NULL && \
231 i < FAILSAFE_ITERATIONS_MED; i++ )
232 {
233 const int localStatus = mgmtFunctions[ i ]( action );
234 if( cryptStatusError( localStatus ) && cryptStatusOK( status ) )
235 status = localStatus;
236
237 /* If we're performing a startup and the kernel is shutting down,
238 bail out now */
239 if( ( action == MANAGEMENT_ACTION_INIT ) && krnlIsExiting() )
240 return( CRYPT_ERROR_PERMISSION );
241 }
242 ENSURES( i < FAILSAFE_ITERATIONS_MED );
243
244 return( status );
245 }
246
247 /* Under various OSes we bind to a number of drivers at runtime. We can
248 either do this sychronously or asynchronously depending on the setting of
249 a config option. By default we use the async init since it speeds up the
250 startup. Synchronisation is achieved by having the open/init functions
251 in the modules that require the drivers call krnlWaitSemaphore() on the
252 driver binding semaphore, which blocks until the drivers are bound if an
253 async bind is in progress, or returns immediately if no bind is in
254 progress */
255
256 #ifdef USE_THREADS
257
threadedBind(const THREAD_PARAMS * threadParams)258 void threadedBind( const THREAD_PARAMS *threadParams )
259 {
260 assert( isReadPtr( threadParams, sizeof( THREAD_PARAMS ) ) );
261
262 ( void ) dispatchManagementAction( asyncInitFunctions,
263 FAILSAFE_ARRAYSIZE( asyncInitFunctions, \
264 MANAGEMENT_FUNCTION ),
265 MANAGEMENT_ACTION_INIT );
266 }
267 #endif /* USE_THREADS */
268
269 /* Perform various sanity checks on the build process. Since this will
270 typically be running on an embedded system there's not much that we can
271 (safely) do in terms of user I/O except to return a special-case return
272 code and hope that the user checks the embedded systems section of the
273 manual for more details, although we do try and produce diagnostic output
274 if this is enabled */
275
buildSanityCheck(void)276 static BOOLEAN buildSanityCheck( void )
277 {
278 FNPTR_DECLARE( void *, testPtr );
279 void *testPtrResult;
280
281 /* If we're using a user-defined endianness override (i.e. it's a cross-
282 compile from a difference architecture) perform a sanity check to
283 make sure that the endianness was set right. The crypto self-test that's
284 performed a few lines further down will catch this problem as well but
285 it's better to do an explicit check here that catches the endianness
286 problem rather than just returning a generic self-test fail error */
287 #if defined( CONFIG_DATA_LITTLEENDIAN ) || defined( CONFIG_DATA_BIGENDIAN )
288 #ifdef DATA_LITTLEENDIAN
289 if( *( ( long * ) "\x80\x00\x00\x00\x00\x00\x00\x00" ) < 0 )
290 #else
291 if( *( ( long * ) "\x80\x00\x00\x00\x00\x00\x00\x00" ) >= 0 )
292 #endif /* DATA_LITTLEENDIAN */
293 {
294 /* We should probably sound klaxons as well at this point */
295 DEBUG_PRINT(( "CPU endianness is configured incorrectly, see "
296 "the cryptlib manual for details" ));
297 return( FALSE );
298 }
299 #endif /* Big/little-endian override check */
300
301 /* Make sure that the compiler doesn't use variable-size enums. This is
302 done by, for example, the PalmOS SDK for backwards compatibility with
303 architectural decisions made for 68K-based PalmPilots, and at least
304 one ARM compiler, as permitted by the ARM AAPCS (section 7.1.3),
305 which says that "this ABI delegates a choice of representation of
306 enumerated types to a platform ABI", followed by a long discussion of
307 all the problems that this causes, after which it's allowed anyway,
308 but it can also be optionally enabled for compilers like gcc, so just
309 to be safe we check all compilers except the ones that we know never
310 do this */
311 #if !defined( _MSC_VER )
312 if( sizeof( CRYPT_ALGO_TYPE ) != sizeof( int ) || \
313 sizeof( CRYPT_MODE_TYPE ) != sizeof( int ) ||
314 sizeof( CRYPT_ATTRIBUTE_TYPE ) != sizeof( int ) )
315 {
316 DEBUG_PRINT(( "Compiler uses variable-length enumerated types, see "
317 "the cryptlib manual for details" ));
318 return( FALSE );
319 }
320 #endif /* Microsoft compilers */
321
322 /* Make sure that the handling of safe function pointers is OK */
323 FNPTR_SET( testPtr, ( void * ) buildSanityCheck );
324 testPtrResult = FNPTR_GET( testPtr );
325 if( testPtrResult != buildSanityCheck )
326 {
327 DEBUG_PRINT(( "Handling of safe function pointers is broken" ));
328 return( FALSE );
329 }
330
331 return( TRUE );
332 }
333
334 /* Initialise and shut down the system */
335
336 CHECK_RETVAL \
initCryptlib(void)337 int initCryptlib( void )
338 {
339 int initLevel = 0, status;
340
341 /* Let the user know that we're in the cryptlib startup code if they're in
342 debug mode */
343 DEBUG_PRINT(( "\n" ));
344 DEBUG_PRINT(( "***************************\n" ));
345 DEBUG_PRINT(( "* Beginning cryptlib init *\n" ));
346 DEBUG_PRINT(( "***************************\n" ));
347
348 /* Perform any required sanity checks on the build process. This would
349 be caught by the self-test but sometimes people don't run this so we
350 perform a minimal sanity check here to avoid failing in the startup
351 self-tests that follow */
352 if( !buildSanityCheck() )
353 {
354 DEBUG_DIAG(( "Build sanity-check failed" ));
355 retIntError();
356 }
357
358 /* Initiate the kernel startup */
359 status = krnlBeginInit();
360 if( cryptStatusError( status ) )
361 {
362 DEBUG_DIAG(( "Kernel init failed" ));
363 return( status );
364 }
365
366 /* Perform OS-specific additional initialisation inside the kernel init
367 lock */
368 status = initSysVars();
369 if( cryptStatusError( status ) )
370 {
371 DEBUG_DIAG(( "OS-specific initialisation failed" ));
372 assert( DEBUG_WARN );
373 krnlCompleteShutdown();
374 return( CRYPT_ERROR_FAILED );
375 }
376
377 /* Perform the multi-phase bootstrap */
378 status = dispatchManagementAction( preInitFunctions,
379 FAILSAFE_ARRAYSIZE( preInitFunctions, \
380 MANAGEMENT_FUNCTION ),
381 MANAGEMENT_ACTION_PRE_INIT );
382 assertNoFault( cryptStatusOK( status ) );
383 if( cryptStatusOK( status ) )
384 {
385 initLevel = 1;
386 status = dispatchManagementAction( initFunctions,
387 FAILSAFE_ARRAYSIZE( initFunctions, \
388 MANAGEMENT_FUNCTION ),
389 MANAGEMENT_ACTION_INIT );
390 assertNoFault( cryptStatusOK( status ) );
391 }
392 if( cryptStatusOK( status ) )
393 {
394 #ifdef USE_THREADS
395 BOOLEAN asyncInit = FALSE;
396 #endif /* USE_THREADS */
397
398 initLevel = 2;
399
400 /* Perform the final init phase asynchronously or synchronously
401 depending on the config option setting. We always send this
402 query to the default user object since no other user objects
403 exist at this time */
404 #ifdef USE_THREADS
405 status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
406 IMESSAGE_GETATTRIBUTE, &asyncInit,
407 CRYPT_OPTION_MISC_ASYNCINIT );
408 if( cryptStatusOK( status ) && asyncInit )
409 {
410 /* We use the kernel's thread storage for this thread, so we
411 specify the thread data storage as NULL */
412 status = krnlDispatchThread( threadedBind, NULL, NULL, 0,
413 SEMAPHORE_DRIVERBIND );
414 if( cryptStatusError( status ) )
415 {
416 /* The thread couldn't be started, try again with a
417 synchronous init */
418 asyncInit = FALSE;
419 }
420 }
421 if( !asyncInit )
422 #endif /* USE_THREADS */
423 status = dispatchManagementAction( asyncInitFunctions,
424 FAILSAFE_ARRAYSIZE( asyncInitFunctions, \
425 MANAGEMENT_FUNCTION ),
426 MANAGEMENT_ACTION_INIT );
427 assertNoFault( cryptStatusOK( status ) );
428 }
429 if( cryptStatusOK( status ) )
430 {
431 #ifndef CONFIG_FUZZ
432 /* Everything's set up, verify that the core crypto algorithms and
433 kernel security mechanisms are working as required, unless we're
434 running a fuzzing build for which we don't want to get held up
435 too long in startup */
436 status = testKernel();
437 assertNoFault( cryptStatusOK( status ) );
438 #endif /* CONFIG_FUZZ */
439 }
440
441 /* If anything failed, shut down the internal functions and services
442 before we exit */
443 if( cryptStatusError( status ) )
444 {
445 if( initLevel >= 1 )
446 {
447 /* Shut down any external interfaces */
448 ( void ) dispatchManagementAction( preShutdownFunctions,
449 FAILSAFE_ARRAYSIZE( preShutdownFunctions, \
450 MANAGEMENT_FUNCTION ),
451 MANAGEMENT_ACTION_PRE_SHUTDOWN );
452 destroyObjects();
453 ( void ) dispatchManagementAction( shutdownFunctions,
454 FAILSAFE_ARRAYSIZE( shutdownFunctions, \
455 MANAGEMENT_FUNCTION ),
456 MANAGEMENT_ACTION_SHUTDOWN );
457 }
458 krnlCompleteShutdown();
459 return( status );
460 }
461
462 /* Complete the kernel startup */
463 krnlCompleteInit();
464
465 /* Let the user know that the cryptlib startup has completed
466 successfully if they're in debug mode */
467 DEBUG_PRINT(( "\n" ));
468 DEBUG_PRINT(( "***************************\n" ));
469 DEBUG_PRINT(( "* cryptlib init completed *\n" ));
470 DEBUG_PRINT(( "***************************\n" ));
471 DEBUG_PRINT(( "\n" ));
472
473 return( CRYPT_OK );
474 }
475
476 CHECK_RETVAL \
endCryptlib(void)477 int endCryptlib( void )
478 {
479 int status;
480
481 /* Initiate the kernel shutdown */
482 status = krnlBeginShutdown();
483 if( cryptStatusError( status ) )
484 return( status );
485
486 /* Reverse the process carried out in the multi-phase bootstrap */
487 ( void ) dispatchManagementAction( preShutdownFunctions,
488 FAILSAFE_ARRAYSIZE( preShutdownFunctions, \
489 MANAGEMENT_FUNCTION ),
490 MANAGEMENT_ACTION_PRE_SHUTDOWN );
491 status = destroyObjects();
492 ( void ) dispatchManagementAction( shutdownFunctions,
493 FAILSAFE_ARRAYSIZE( shutdownFunctions, \
494 MANAGEMENT_FUNCTION ),
495 MANAGEMENT_ACTION_SHUTDOWN );
496
497 /* Complete the kernel shutdown */
498 krnlCompleteShutdown();
499 return( status );
500 }
501