diff --git a/pkg/systemd/overview-cards/cryptoPolicies.jsx b/pkg/systemd/overview-cards/cryptoPolicies.jsx
index dc8b996ec785..1db1e19b16a7 100644
--- a/pkg/systemd/overview-cards/cryptoPolicies.jsx
+++ b/pkg/systemd/overview-cards/cryptoPolicies.jsx
@@ -18,7 +18,7 @@
*/
import cockpit from "cockpit";
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { Modal } from "@patternfly/react-core/dist/esm/components/Modal/index.js";
@@ -29,6 +29,7 @@ import { ModalError } from 'cockpit-components-inline-notification.jsx';
import { PrivilegedButton } from "cockpit-components-privileged.jsx";
import { ProfilesMenuDialogBody } from "./profiles-menu-dialog-body.jsx";
import { useDialogs } from "dialogs.jsx";
+import { useInit } from "hooks";
import "./cryptoPolicies.scss";
@@ -37,63 +38,87 @@ const _ = cockpit.gettext;
const displayProfileText = profile => profile === "DEFAULT" ? _("Default") : profile;
const isInconsistentPolicy = (policy, fipsEnabled) => policy === "FIPS" !== fipsEnabled;
+const getFipsConfigurable = () => cockpit.spawn(["/bin/sh", "-c", "command -v fips-mode-setup"], { error: "ignore" })
+ .then(() => true)
+ .catch(() => false);
+
export const CryptoPolicyRow = () => {
const Dialogs = useDialogs();
const [currentCryptoPolicy, setCurrentCryptoPolicy] = useState(null);
const [fipsEnabled, setFipsEnabled] = useState(null);
+ const [fipsConfigurable, setFipsConfigurable] = useState(null);
const [shaSubPolicyAvailable, setShaSubPolicyAvailable] = useState(null);
- useEffect(() => {
+ useInit(() => {
cockpit.file("/proc/sys/crypto/fips_enabled").read()
.then(content => setFipsEnabled(content ? content.trim() === "1" : false));
- cockpit.file("/etc/crypto-policies/state/current")
- .watch(content => setCurrentCryptoPolicy(content ? content.trim() : null));
+ getFipsConfigurable().then(v => setFipsConfigurable(v));
+ cockpit.file("/etc/crypto-policies/config")
+ .watch(async contents => {
+ // Ask crypto-policies to get correct FIPS state, as that dominates the configured policy
+ try {
+ setCurrentCryptoPolicy((await cockpit.spawn(["update-crypto-policies", "--show"])).trim());
+ } catch (error) {
+ console.warn("Failed to get current crypto policy:", error.toString(),
+ "; falling back to /etc/crypto-policies/config");
+ setCurrentCryptoPolicy(contents.trim());
+ }
+ });
// RHEL-8-8 has no SHA1 subpolicy
cockpit.file("/usr/share/crypto-policies/policies/modules/SHA1.pmod").read()
.then(content => setShaSubPolicyAvailable(content ? content.trim() : false));
- }, []);
+ });
- if (!currentCryptoPolicy) {
+ if (currentCryptoPolicy === null || fipsEnabled === null || fipsConfigurable === null)
return null;
- }
+
+ const policyRender = (currentCryptoPolicy.startsWith("FIPS") && !fipsConfigurable)
+ /* read-only mode; can't switch away from FIPS without fips-mode-setup */
+ ? {displayProfileText(currentCryptoPolicy)}
+ : Dialogs.show()}>
+ {displayProfileText(currentCryptoPolicy)}
+ ;
return (
{_("Cryptographic policy")} |
-
- Dialogs.show()}>
- {displayProfileText(currentCryptoPolicy)}
-
- |
+ {policyRender} |
);
};
-const setPolicy = (policy, setError, setInProgress) => {
+const setPolicy = async (policy, setError, setInProgress, fipsConfigurable) => {
setInProgress(true);
- let promise;
- if (policy === "FIPS") {
- promise = cockpit.spawn(["fips-mode-setup", "--enable"], { superuser: "require", err: "message" });
- } else {
- promise = cockpit.spawn(["fips-mode-setup", "--disable"], { superuser: "require", err: "message" }).then(() =>
- cockpit.spawn(["update-crypto-policies", "--set", policy], { superuser: "require", err: "message" }));
- }
+ try {
+ if (policy === "FIPS") {
+ cockpit.assert(fipsConfigurable, "calling setPolicy(FIPS) without fips-mode-setup");
+ await cockpit.spawn(["fips-mode-setup", "--enable"], { superuser: "require", err: "message" });
+ } else {
+ if (fipsConfigurable)
+ await cockpit.spawn(["fips-mode-setup", "--disable"], { superuser: "require", err: "message" });
+ await cockpit.spawn(["update-crypto-policies", "--set", policy], { superuser: "require", err: "message" });
+ }
- promise.then(() => cockpit.spawn(["shutdown", "--reboot", "now"], { superuser: "require", err: "message" }))
- .catch(error => setError(error))
- .finally(() => setInProgress(false));
+ await cockpit.spawn(["shutdown", "--reboot", "now"], { superuser: "require", err: "message" });
+ } catch (error) {
+ setError(error);
+ } finally {
+ setInProgress(false);
+ }
};
const CryptoPolicyDialog = ({
currentCryptoPolicy,
fipsEnabled,
+ fipsConfigurable,
reApply,
shaSubPolicyAvailable,
}) => {
@@ -125,6 +150,8 @@ const CryptoPolicyDialog = ({
const policies = Object.keys(cryptopolicies)
.filter(pol => pol.endsWith(':SHA1') ? shaSubPolicyAvailable : true)
+ // cannot enable fips without fips-mode-setup
+ .filter(pol => pol.startsWith("FIPS") ? fipsConfigurable : true)
.map(policy => ({
name: policy,
title: displayProfileText(policy),
@@ -185,7 +212,8 @@ const CryptoPolicyDialog = ({
{_("Applying new policy... This may take a few minutes.")}
}
-