Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/ipahealthcheck/ipa/certs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from ipalib.install import certmonger
from ipalib.constants import RENEWAL_CA_NAME, IPA_CA_RECORD
from ipaplatform.paths import paths
from ipaplatform.tasks import tasks
from ipaserver.install import certs
from ipaserver.install import dsinstance
from ipaserver.install import krainstance
Expand Down Expand Up @@ -1568,3 +1569,68 @@ def check(self):

if len(requests) == 0:
yield Result(self, constants.SUCCESS, key='no_stuck')


@registry
class CertmongerFIPSTokensCheck(IPAPlugin):
"""Check if the current FIPS state doesn't match the certmonger
token name. This only applies if an HSM is not used for now.

We can only test this on certificates stored in NSS dbs.
"""
requires = ('dirsrv',)

@duration
def check(self):
# token names we care about
candidates = ('NSS FIPS 140-2 Certificate DB', 'NSS Certificate DB')

if tasks.is_fips_enabled():
expected_token = 'NSS FIPS 140-2 Certificate DB'
else:
expected_token = 'NSS Certificate DB'

# Getting the requests this way instead of get_expected_requests
# because we need to be able to modify the list in tests and this
# is only currently possible doing it this way.

cm = certmonger._certmonger()
requests = cm.obj_if.get_requests()
failed = False
for request in requests:
req = certmonger._cm_dbus_object(cm.bus, cm, request,
certmonger.DBUS_CM_REQUEST_IF,
certmonger.DBUS_CM_IF, True)
request_id = str(req.prop_if.Get(certmonger.DBUS_CM_REQUEST_IF,
'nickname'))
if request_id is None:
# we could log here but other checks already do. Don't spam.
continue

storage = certmonger.get_request_value(request_id,
'key-storage')

if storage != 'NSSDB':
logger.debug('Skipping non-NSSDB request %s',
request_id)
continue

token = certmonger.get_request_value(request_id,
'key-token')
if token not in candidates:
logger.debug('Skipping token %s in request %s',
str(token), request_id)
continue

if token != expected_token:
yield Result(self, constants.ERROR,
key=request_id,
token=token,
expected_token=expected_token,
msg='certmonger request {key} has token {token} '
'but based on the current FIPS state the '
'expected token is {expected_token}')
failed = True

if not failed:
yield Result(self, constants.SUCCESS, key='fipstokencheck')
168 changes: 166 additions & 2 deletions tests/test_ipa_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@

from ipahealthcheck.core import constants, config
from ipahealthcheck.ipa.plugin import registry
from ipahealthcheck.ipa.certs import IPACertTracking, CertmongerStuckCheck
from unittest.mock import Mock
from ipahealthcheck.ipa.certs import (
IPACertTracking,
CertmongerStuckCheck,
CertmongerFIPSTokensCheck
)
from unittest.mock import Mock, patch
from mock_certmonger import create_mock_dbus, _certmonger
from mock_certmonger import get_expected_requests, set_requests

Expand Down Expand Up @@ -128,3 +132,163 @@ def test_one_stuck(self):
result = self.results.results[0]
assert result.result == constants.WARNING
assert result.kw.get('key') == '7777'


class TestFIPSTokens(BaseTest):
"""Test the combination of FIPS configurations with tokens and
also that when HSM is used the check is skipped.
"""
patches = {
'ipahealthcheck.ipa.certs.get_expected_requests':
Mock(return_value=get_expected_requests()),
'ipalib.install.certmonger._cm_dbus_object':
Mock(side_effect=create_mock_dbus),
'ipalib.install.certmonger._certmonger':
Mock(return_value=_certmonger())
}

nss_tracking = {
'nickname': '9876',
'ca-name': 'dogtag-ipa-ca-renew-agent',
'template_profile': 'caIPAserviceCert',
'cert-storage': 'NSSDB',
'cert-storage_location': '/etc/pki/pki-tomcat/alias',
'cert-token': 'NSS Certificate DB',
'key-storage': 'NSSDB',
'key-storage_location': '/etc/pki/pki-tomcat/alias',
'key-token': 'NSS Certificate DB',
}

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_nonfips_token_correct(self, mock_value, mock_fips):
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'NSS Certificate DB',
]
mock_fips.return_value = False
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.SUCCESS

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_nonfips_token_wrong(self, mock_value, mock_fips):
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'NSS FIPS 140-2 Certificate DB',
]
mock_fips.return_value = False
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.ERROR
assert result.kw.get('key') == '9876'
assert result.kw.get('token') == 'NSS FIPS 140-2 Certificate DB'

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_fips_token_correct(self, mock_value, mock_fips):
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'NSS FIPS 140-2 Certificate DB',
]
mock_fips.return_value = True
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.SUCCESS

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_fips_token_wrong(self, mock_value, mock_fips):
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'NSS Certificate DB',
]
mock_fips.return_value = True
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.ERROR
assert result.kw.get('key') == '9876'
assert result.kw.get('token') == 'NSS Certificate DB'
assert result.kw.get('expected_token') == \
'NSS FIPS 140-2 Certificate DB'

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_hsm_token_non_fips(self, mock_value, mock_fips):
"""FIPS shouldn't make a difference as HSM tokens should be skipped"""
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'ipa_token',
]
mock_fips.return_value = False
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.SUCCESS

@patch('ipahealthcheck.ipa.certs.tasks.is_fips_enabled')
@patch('ipalib.install.certmonger.get_request_value')
def test_hsm_token_fips(self, mock_value, mock_fips):
"""FIPS shouldn't make a difference as HSM tokens should be skipped"""
mock_value.side_effect = [
'FILE',
'FILE',
'NSSDB', 'ipa_token',
]
mock_fips.return_value = True
set_requests(add=self.nss_tracking)

framework = object()
registry.initialize(framework, config.Config)
f = CertmongerFIPSTokensCheck(registry)

self.results = capture_results(f)

assert len(self.results) == 1
result = self.results.results[0]
assert result.result == constants.SUCCESS