Skip to content

Commit 42e197f

Browse files
ifranzkijschmidb
authored andcommitted
Initialize mechanism list before initializing OpenSSL in icainit
In libica's library constructor OpenSSL is initialized since commit 05c4e36 "Ensure OpenSSL config is loaded before creating libica's own library context". This will also cause OpenSSL to evaluate the OpenSSL config file and load providers configured there. Even without this commit, it can happen when libica is in FIPS mode, that OpenSSL gets implicitly initialized by OpenSSL usage within the FIPS power on tests, which run as part of the library constructor. If OpenSSL has been initialized by the application already, then the attempt to initialize OpenSSL again by libica is a no-operation. However, if the libica constructor is the very first to initialize OpenSSL this can cause problems. For applications that link against libica (via -lica), the libica library constructor is run before the applications main function, and thus it will most likely be the very first OpenSSL initialization attempt. If the IBMCA provider is configured in the OpenSSL config file, then it is loaded and initialized during OpenSSL initialization triggered by the libica constructor. During IBMCA provider initialization, it loads libica and queries libica's mechanism list. The problem is that this happens while we are still in the middle of the libica library constructor, and haven't fully initialized libica. Especially the mechanism list has not yet been set up, and thus the IBMCA provider will get a mechanism list where all algorithms are marked as being not supported. The IBMCA provider will thus not register any of its algorithms, and thus can not be used subsequentially by the application. Unfortunately OpenSSL evaluates the config file only once, and also the IBMCA provider queries the libica mechanism list only once, so the situation will not change for the lifetime of the calling application. To fix this, make sure that the mechanism list is initialized before the libica constructor initializes OpenSSL. That way, the IBMCA provider loaded due to the OpenSL initialization attempt from within the libica library constructor will get a valid mechanism list. Since some mechanisms are dependent on the FIPS flag of libica, it must evaluate the system's FIPS state before it initializes OpenSSL, but finalize the FIPS setup (loading the FIPS provider, etc) only after OpenSSL has been initialized. For that the fips_init() function has been split into two parts. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
1 parent 50ca5f0 commit 42e197f

3 files changed

Lines changed: 35 additions & 15 deletions

File tree

src/fips.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ SHA3_KAT(512, 512);
249249
#endif
250250

251251
void
252-
fips_init(void)
252+
fips_get_indicator(void)
253253
{
254254
FILE *fd;
255255
char fips_flag;
@@ -271,44 +271,46 @@ fips_init(void)
271271
fips_flag = '1';
272272

273273
if (fips_flag - '0') {
274-
#if !OPENSSL_VERSION_PREREQ(3, 0)
275274
/* Set libica into FIPS mode. */
276275
fips |= ICA_FIPS_MODE;
276+
}
277+
}
277278

279+
void
280+
fips_init(void)
281+
{
282+
if (fips & ICA_FIPS_MODE) {
283+
#if !OPENSSL_VERSION_PREREQ(3, 0)
278284
/* Try to set OpenSSL into FIPS mode. If this is not possible,
279285
* all software fallbacks (including RSA key generation) will
280286
* be disabled. OpenSSL FIPS mode can be queried using the
281287
* FIPS_mode() function. */
282288
FIPS_mode_set(1);
283289
#else
284-
fips = 0;
285-
286290
#ifndef NO_FIPS_CONFIG_LOAD
287291
/* Allow to skip reading the openssl 3.x fips config. Tests showed
288292
* that this step must be skipped on RHEL9 systems. But on other
289293
* systems, or with a locally built openssl, this step is necessary. */
290294
if (!OSSL_LIB_CTX_load_config(openssl_libctx, LIBICA_FIPS_CONFIG)) {
291295
syslog(LOG_ERR, "Libica failed to load openssl fips config %s\n",
292296
LIBICA_FIPS_CONFIG);
293-
fips |= ICA_FIPS_INTEGRITY;
297+
fips = ICA_FIPS_INTEGRITY;
294298
return;
295299
}
296300
#endif
297301

298302
openssl_provider = OSSL_PROVIDER_load(openssl_libctx, "fips");
299303
if (openssl_provider == NULL) {
300304
syslog(LOG_ERR, "Libica failed to load fips provider.\n");
301-
fips |= ICA_FIPS_INTEGRITY;
305+
fips = ICA_FIPS_INTEGRITY;
302306
return;
303307
}
304308

305309
if (!EVP_set_default_properties(openssl_libctx, "fips=yes")) {
306310
syslog(LOG_ERR, "Libica failed to set default properties 'fips=yes'\n");
307-
fips |= ICA_FIPS_INTEGRITY;
311+
fips = ICA_FIPS_INTEGRITY;
308312
return;
309313
}
310-
311-
fips |= ICA_FIPS_MODE;
312314
#endif
313315
} else {
314316
/* kernel fips flag == 0, load default provider in case we are

src/include/fips.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ int openssl_in_fips_mode(void);
2525
* Initialize global fips var to 1 resp. 0 when FIPS_FLAG is 1 resp. 0 (or not
2626
* present).
2727
*/
28+
void fips_get_indicator(void);
2829
void fips_init(void);
2930

3031
/*

src/init.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ void __attribute__ ((constructor)) icainit(void)
113113
if (ptr && sscanf(ptr, "%i", &value) == 1)
114114
ica_set_stats_mode(value);
115115

116+
#ifdef ICA_FIPS
117+
fips_get_indicator();
118+
#endif
119+
120+
rng_init();
121+
122+
s390_prng_init();
123+
124+
s390_initialize_functionlist();
125+
116126
#if OPENSSL_VERSION_PREREQ(3, 0)
117127
/*
118128
* OpenSSL >= 3.0:
@@ -124,6 +134,18 @@ void __attribute__ ((constructor)) icainit(void)
124134
* is loaded later, which may cause that all configured providers
125135
* are also loaded into the library context. We need to make sure that
126136
* only the default or fips provider is loaded in the library context.
137+
*
138+
* Also make sure that OpenSSL initialization happens AFTER the
139+
* mechanism list has been initialized and the fips indicator has been
140+
* obtained. OPENSSL_init_crypto may load configured providers, and a
141+
* provider might use libica in its initialization function. It must
142+
* be ensured that libica has been initialized that far before OpenSSL
143+
* is initialized, so that such libica calls from providers can be
144+
* fulfilled and return correct information.
145+
*
146+
* The remaining FIPS initialization (fips provider load, power on self
147+
* tests, etc) must still happen after OpenSSL initialization, because
148+
* that relies on OpenSSL being initialized.
127149
*/
128150
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
129151

@@ -135,18 +157,13 @@ void __attribute__ ((constructor)) icainit(void)
135157
#endif
136158

137159
#ifdef ICA_FIPS
138-
fips_init(); /* before powerup tests and initialize functionlist */
160+
fips_init();
139161
#endif
140162

141163
#if OPENSSL_VERSION_PREREQ(3, 0)
142164
openssl3_initialized = 1;
143165
#endif
144166

145-
rng_init();
146-
147-
s390_prng_init();
148-
149-
s390_initialize_functionlist();
150167

151168
#ifdef ICA_FIPS
152169
if (fips & ICA_FIPS_MODE)

0 commit comments

Comments
 (0)