Bug 1831033

Summary: nss does not return proper fips mode value before calling NSS_Initialize()
Product: Red Hat Enterprise Linux 8 Reporter: Paul Wouters <pwouters>
Component: nssAssignee: nss-nspr-maint <nss-nspr-maint>
Status: CLOSED CURRENTRELEASE QA Contact: Ivan Nikolchev <inikolch>
Severity: unspecified Docs Contact:
Priority: medium    
Version: 8.3CC: cagney, cagney, dueno, inikolch, rrelyea, ssorce, tis
Target Milestone: rcKeywords: Triaged
Target Release: 8.0Flags: pm-rhel: mirror+
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: nss-3.53.1-11.el8_2 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2020-09-22 12:20:54 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Paul Wouters 2020-05-04 13:56:58 UTC
Calling PK11_IsFIPS() before NSS_Initialize() always returns false.

I suspect the code return (fips && db-in-fips) and since no db is opened yet, it returns false.

Once libreswan has called NSS_Initialize(), subsequent calls to PK11_IsFIPS() returns true as expected.

libreswan needs to know the fips status before opening the nss db because it is enforcing some things, such as disabling the logging of private key material and filtering the IKE algorithms available. The slot name is also different so for using the nsspassword file we also need to know if we are opening a fips nss db or a non-fips one.

Comment 1 Bob Relyea 2020-05-04 15:33:07 UTC
NSS doesn't know the FIPS state before NSS_Initialize is called. It might be able to return the system FIPS state, but it doesn't know what the database FIPS state is because it is stored in the database.

Comment 2 Bob Relyea 2020-05-04 15:36:40 UTC
> libreswan needs to know the fips status before opening the nss db because it is enforcing some things, such as disabling the logging of private key material
> and filtering the IKE algorithms available. The slot name is also different so for using the nsspassword file we also need to know if we are opening a 
> fips nss db or a non-fips one.

Why does these things have to happen before NSS_Initialize is called? You don't need a password an NSS_Initialize time? NSS can't give you the FIPS state without you first giving the db.

bob

Comment 3 Paul Wouters 2020-05-04 16:11:33 UTC
The fips status is "whether the system is in fips mode" and "if the nss database is in fips mode"

Why can't it just return the status of 'whether the system is in fips mode" if a database has not yet been opened ?

Our problem is that to open the database, we need to read and parse the config file. Some of our tools don't even really know about this.

I am looking at moving up the NSS_Initialize() call.

Our tool algparse howver, doesnt even read a config file, so it can never find or open the database. We still want it to act differently under fips mode.
So either we have to put back code to read the /proc file ourselves, or NSS could just return that if no database is opened.

Comment 4 Bob Relyea 2020-05-04 16:20:24 UTC
No, that's now what NSS_IsFIPS returns. It returns is *NSS* in FIPS mode, which is undefined until NSS is initialized.


> Our tool algparse howver, doesnt even read a config file, so it can never find or open the database. We still want it to act differently under fips mode.
> So either we have to put back code to read the /proc file ourselves, or NSS could just return that if no database is opened.

Sigh, in both cases you will get inconsistent behavior is your database is in FIPS mode and the system is not.

Comment 5 Simo Sorce 2020-05-04 16:27:56 UTC
(In reply to Bob Relyea from comment #4)
> No, that's now what NSS_IsFIPS returns. It returns is *NSS* in FIPS mode,
> which is undefined until NSS is initialized.
> 
> 
> > Our tool algparse howver, doesnt even read a config file, so it can never find or open the database. We still want it to act differently under fips mode.
> > So either we have to put back code to read the /proc file ourselves, or NSS could just return that if no database is opened.
> 
> Sigh, in both cases you will get inconsistent behavior is your database is
> in FIPS mode and the system is not.

To be honest this is not important, Security Policies clearly define what is required, which include a db in FIPS mode.
If the cryptography officer messes up the system it is their fault.

Unless there is a possible pitfal where a tool would do the wrong thing at install time with this behavior, I would not be concerned about a potential inconsistency like this, because it is an invalid mode anyway.

To me it sounds like there are less chances software will do the wrong thing if they know the status they are supposed to operate in.
For example if they "known" the system is in FIPS moe and later they opena db that is not they could return an error.
But without an indication of what status they are supposed to b in they wouldn't be able to tell whether the db is in the correct state or not anyway.

Comment 6 Bob Relyea 2020-05-04 16:47:04 UTC
It just makes testing harder. Anyway if libreswan wants to ignore the NSS FIPS state and only flip on the system state, there is no reason for it not to read /proc/sys/crypto/fips_enabled itself.

Comment 7 Bob Relyea 2020-05-04 16:48:03 UTC
The only reason to use NSS_IsFIPS to to make sure your view of FIPS and NSS is consistant.

Comment 8 Paul Wouters 2020-05-04 16:52:58 UTC
For our tools that do not open ipsec.conf, Andrew pointed out we can use NSS_NoDB_Init(".");

Comment 9 Cagney 2020-05-04 16:56:03 UTC
here's some code from fipscheck
        /*
         * While, technically, NSS_NoDB_Init() is idenpotent, perform
         * an explicit test.
         */
        if (!NSS_IsInitialized()) {
                errno = 0; debug_log("Initializing NSS"); 
                NSS_NoDB_Init(".");
        }
                if (!PK11_IsFIPS()) {
                        errno = 0; debug_log("Enabling NSS FIPS mode");
                        SECMODModule *internal = SECMOD_GetInternalModule();
                        if (internal == NULL) {
                                errno = 0; debug_log("SECMOD_GetInternalModule() failed");
                                return -1;
                        }
                        if (SECMOD_DeleteInternalModule(internal->commonName) != SECSuccess) {
                                errno = 0; debug_log("SECMOD_DeleteInternalModule(%s) failed",
                                                     internal->commonName);
                                return -1;
                        }
                        if (!PK11_IsFIPS()) {
                                errno = 0; debug_log("NSS FIPS mode toggle failed");
                                return -1;
                        }
                }
                static int logged = 0;
                if (!logged) {
                        errno = 0; debug_log("NSS FIPS mode enabled");
                        logged = 1;
                }
stripped back (no need to flip mode), it should be possible to get algparse working.  And by adding a close probe what mode NSS things it is in.

Comment 10 Bob Relyea 2020-05-04 17:03:51 UTC
In that case NSS is only in FIPS mode if the system is in FIPS mode.

SECStatus ike_isFIPS(PRBool *isFIPS)
{
     *isFIPS = PR_FALSE;
     if (!NSS_IsInitialized()) {
        SECStatus rv = NSS_NoDB_Init(".");
        if (rv != SECSuccess) {
            *isFIPS = PR_TRUE; /* if NSS_NoDB_Init failed to initial, it means that we are in FIPS mode and the POST failed */
            return rv;
        }
        *isFIPS = NSS_IsFIPS();
        return NSS_Shutdown();
     }
     *isFIPS = NSS_IsFIPS();
     return SECSuccess;
}

This will return the FIPS mode of the current database. If the database is not initialized, it will return the state /proc/sys/crypto/fips_enabled. If it fails it means that the system is in FIPS mode and the NSS self-tests failed, or there is something very wrong with NSS (NSS_Shutdown can fail, but only if you shutdown while holding NSS objects open, not objects are accessed between Init and shutdown).

bob

Comment 11 Simo Sorce 2020-05-04 17:07:04 UTC
(In reply to Bob Relyea from comment #6)
> It just makes testing harder. Anyway if libreswan wants to ignore the NSS
> FIPS state and only flip on the system state, there is no reason for it not
> to read /proc/sys/crypto/fips_enabled itself.

There is, we do not want non-crypto-modules to use random interfaces, so we can change this detail and only have to change the cryptography modules.
This is something we decided as a team a while ago when dealing with leapp upgrades, as we need to change how we are checking fips mode and found way too many user space application doing it on their own, making it really hard for us to make any system-wide changes in RHEL-8 and later RHEL-9.

This is why we opened bugs like #1816265

Comment 12 Paul Wouters 2020-05-04 18:34:14 UTC
for libreswan, we work around this now. note that libreswan also uses modutil to set nss into fips mode for testing. So please don't rmeove that functionality :)

Comment 13 Bob Relyea 2020-05-04 22:36:39 UTC
That functionality is pretty baked into NSS, so you should be fine. Your not the only one that depends on it either;).

Comment 14 Bob Relyea 2020-05-18 23:19:49 UTC
In NSS upstream there's a new call that just returns the system state. Moving this to post. it's in NSS 3.53, not 3.52, however.