Skip to content

Commit

Permalink
Merge pull request #214 from pridhiviraj/new
Browse files Browse the repository at this point in the history
Trustedboot testcases and enhancements to SB tests.
  • Loading branch information
stewartsmith authored Apr 4, 2018
2 parents e07be65 + a5f77a4 commit 828c53c
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 27 deletions.
6 changes: 5 additions & 1 deletion OpTestConfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,11 @@ def get_parser():

stbgroup = parser.add_argument_group('STB', 'Secure and Trusted boot parameters')
stbgroup.add_argument("--un-signed-pnor", help="Unsigned or improperly signed PNOR")
stbgroup.add_argument("--signed-pnor", help="Properly signed PNOR image(devel)")
stbgroup.add_argument("--signed-pnor", help="Properly signed PNOR image(imprint)")
stbgroup.add_argument("--signed-to-pnor", help="Properly signed PNOR image(imprint or production)")
stbgroup.add_argument("--key-transition-pnor", help="Key transition PNOR image")
stbgroup.add_argument("--test-container", nargs=2, metavar=("PART name", "bin file"), action='append',
help="PNOR partition container to flash, Ex: --test-container CAPP capp_unsigned.bin")
stbgroup.add_argument("--secure-mode", action='store_true', default=False, help="Secureboot mode")
stbgroup.add_argument("--trusted-mode", action='store_true', default=False, help="Trustedboot mode")

Expand Down Expand Up @@ -355,6 +358,7 @@ def objs(self):
else:
raise Exception("Unsupported BMC Type")

host.set_system(self.op_system)
return

def bmc(self):
Expand Down
2 changes: 2 additions & 0 deletions common/OpTestHost.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def username(self):
def password(self):
return self.passwd

def set_system(self, system):
self.ssh.set_system(system)

def get_scratch_disk(self):
return self.scratch_disk
Expand Down
12 changes: 12 additions & 0 deletions common/OpTestIPMI.py
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,9 @@ def set_tpm_required(self):
def clear_tpm_required(self):
pass

def is_tpm_enabled(self):
pass

def ipmi_get_golden_side_sensor_id(self):
cmd = "sdr elist -v | grep -i 'BIOS Golden'"
output = self.ipmitool.run(cmd)
Expand Down Expand Up @@ -1411,3 +1414,12 @@ def set_tpm_required(self):

def clear_tpm_required(self):
self.ipmitool.run('raw 0x04 0x30 0x49 0x10 0x00 0x01 0 0 0 0 0 0')

def is_tpm_enabled(self):
res = self.ipmitool.run("sdr elist | grep -i TPM")
if "State Deasserted" in res:
print "#TPM is disabled"
return False
elif "State Asserted" in res:
print "#TPM is enabled"
return True
18 changes: 18 additions & 0 deletions common/OpTestSystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,15 @@ def get_my_ip_from_host_perspective(self):
print "hostname -i does not provide valid IP, correct and proceed with installation"
return my_ip

def sys_enable_tpm(self):
self.cv_IPMI.set_tpm_required()

def sys_disable_tpm(self):
self.cv_IPMI.clear_tpm_required()

def sys_is_tpm_enabled(self):
return self.cv_IPMI.is_tpm_enabled()

class OpTestFSPSystem(OpTestSystem):
'''
Implementation of an OpTestSystem for IBM FSP based systems (such as Tuleta and ZZ)
Expand Down Expand Up @@ -1441,6 +1450,15 @@ def sys_warm_reset(self):
def sys_cold_reset_bmc(self):
self.rest.bmc_reset()

def sys_enable_tpm(self):
self.rest.enable_tpm()

def sys_disable_tpm(self):
self.rest.disable_tpm()

def sys_is_tpm_enabled(self):
return self.rest.is_tpm_enabled()

class OpTestQemuSystem(OpTestSystem):
'''
Implementation of OpTestSystem for the Qemu Simulator
Expand Down
14 changes: 11 additions & 3 deletions op-test
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ from testcases import OpTestCAPI
from testcases import gcov
from testcases import OpalSysfsTests
from testcases import SecureBoot
from testcases import TrustedBoot
import testcases

args, remaining_args = OpTestConfiguration.conf.parse_args(sys.argv)
Expand Down Expand Up @@ -124,6 +125,7 @@ class SkirootSuite():
self.s = unittest.TestSuite()
self.s.addTest(DeviceTreeWarnings.Skiroot())
self.s.addTest(SecureBoot.VerifyOPALSecureboot())
self.s.addTest(TrustedBoot.VerifyOPALTrustedBoot())
self.s.addTest(OpTestEM.skiroot_suite())
self.s.addTest(OpTestInbandIPMI.skiroot_full_suite())
self.s.addTest(OpTestInbandUsbInterface.skiroot_full_suite())
Expand Down Expand Up @@ -199,11 +201,16 @@ class BasicIPLSuite():
def suite(self):
return BasicIPL.suite()

class STBSuite():
'''Secure and Trusted boot tests'''
class SBSuite():
'''Secure boot tests'''
def suite(self):
return SecureBoot.secureboot_suite()

class TBSuite():
'''Trusted boot tests'''
def suite(self):
return TrustedBoot.trustedboot_suite()

class DefaultSuite():
'''Basic regression tests'''
def __init__(self):
Expand Down Expand Up @@ -395,7 +402,8 @@ suites = {
'qemu' : QemuSuite(),
'BasicIPL' : BasicIPLSuite(),
'BasicPCI' : BasicPCISuite(),
'stb' : STBSuite(),
'secure-boot' : SBSuite(),
'trusted-boot' : TBSuite(),
'em' : OpTestEMSuite(),
'known-bugs' : KnownBugs(),
'experimental': ExperimentalSuite(),
Expand Down
3 changes: 1 addition & 2 deletions testcases/OpTestFlash.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def setUp(self):

def validate_side_activated(self):
l_bmc_side, l_pnor_side = self.cv_IPMI.ipmi_get_side_activated()
self.cv_IPMI.ipmi_get_golden_side_sensor_id()
self.assertIn(BMC_CONST.PRIMARY_SIDE, l_bmc_side, "BMC: Primary side is not active")
if (l_pnor_side == BMC_CONST.GOLDEN_SIDE):
print "PNOR: Primary side is not active"
Expand All @@ -79,7 +78,7 @@ def validate_side_activated(self):
boot_count_sensor = self.cv_IPMI.ipmi_get_boot_count_sensor_id()
self.assertNotEqual(boot_count_sensor, None, "Failed to get the Boot Count sensor id")
self.cv_IPMI.ipmi_set_pnor_primary_side(bios_sensor, boot_count_sensor)
l_bmc_side, l_pnor_side = self.cv_IPMI.ipmi_get_side_activated()
l_bmc_side, l_pnor_side = self.cv_IPMI.ipmi_get_side_activated()
self.assertIn(BMC_CONST.PRIMARY_SIDE, l_pnor_side, "PNOR: Primary side is not active")

def get_pnor_level(self):
Expand Down
16 changes: 0 additions & 16 deletions testcases/OpTestRTCdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ def runTest(self):
self.cv_HOST.host_read_hwclock()
self.hwclock_adjust()
self.cv_HOST.host_read_hwclock()
self.hwclock_compare()
self.cv_HOST.host_read_hwclock()

##
# @brief This function reads hwclock from special /dev/... file instead of default
Expand Down Expand Up @@ -248,20 +246,6 @@ def hwclock_in_localtime(self):
except CommandFailed as c:
self.assertEqual(c.exitcode, 0, "Keeping the hwclock in localtime is failed: %s" % str(c))

##
# @brief This function tests hwclock compare functionality for a time of 100 seconds.
# Here checking the return status of timeout as 124, if compare works fine. any
# other return value means compare function failed.
def hwclock_compare(self):
print "Testing hwclock compare functionality for a time of 10 seconds"
exitcode = 0
err = "hwclock compare function succeeded, expected exit code of 124"
try:
self.cv_HOST.host_run_command("timeout 10 hwclock --compare")
except CommandFailed as c:
exitcode = c.exitcode
err = "hwclock compare function failed: %s" % str(c)
self.assertEqual(exitcode, 124, err)

##
# @brief This function predict RTC reading at time given with --date
Expand Down
2 changes: 1 addition & 1 deletion testcases/SbePassThrough.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def setUp(self):

def setup_init(self):
self.c.run_command("dmesg -D")
self.cpu = ''.join(self.c.run_command("grep '^cpu' /proc/cpuinfo |uniq|sed -e 's/^.*: //;s/ .*//;'"))
self.cpu = ''.join(self.c.run_command("grep '^cpu' /proc/cpuinfo |uniq|sed -e 's/^.*: //;s/[,]* .*//;'"))

if self.cpu not in ["POWER9"]:
self.skipTest("SBE passthrough test not supported on %s" % self.cpu)
Expand Down
96 changes: 92 additions & 4 deletions testcases/SecureBoot.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from common.OpTestConstants import OpTestConstants as BMC_CONST
from common.Exceptions import CommandFailed
from testcases.OpTestFlash import PNORFLASH
from testcases.OpTestFlash import OpalLidsFLASH

class SecureBoot(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -60,6 +61,13 @@ def verify_boot_fail(self):
return False
return True

def wait_for_secureboot_enforce(self):
console = self.cv_SYSTEM.sys_get_ipmi_console().get_console()
self.cv_SYSTEM.sys_power_on()
console.expect("STB: secure mode enforced, aborting.", timeout=300)
console.expect("secondary_wait", timeout=20)
console.expect("host_voltage_config", timeout=100)

def wait_for_sb_kt_start(self):
console = self.cv_SYSTEM.sys_get_ipmi_console().get_console()
console.expect("sbe|Performing Secure Boot key transition", timeout=300)
Expand All @@ -71,15 +79,25 @@ def wait_for_shutdown(self):
def verify_opal_sb(self):
c = self.cv_SYSTEM.sys_get_ipmi_console()
self.cv_SYSTEM.host_console_unique_prompt()

c.run_command("stty cols 300; stty rows 30;")
self.cpu = ''.join(c.run_command("grep '^cpu' /proc/cpuinfo |uniq|sed -e 's/^.*: //;s/[,]* .*//;'"))
print self.cpu
if self.cpu in ["POWER9"]:
part_list = ["CAPP", "IMA_CATALOG", "BOOTKERNEL", "VERSION"]
elif self.cpu in ["POWER8"]:
part_list = ["CAPP", "BOOTKERNEL"]
else:
self.skipTest("OPAL SB test not supported on %s" % self.cpu)

data = " ".join(c.run_command("cat /sys/firmware/opal/msglog | grep -i stb"))
part_list = ["CAPP", "IMA_CATALOG", "BOOTKERNEL", "VERSION"]
if self.securemode:
if not "secure mode on" in data:
self.assertTrue(False, "OPAL: Secure mode is detected as OFF")
self.assertTrue(False, "OPAL-SB: Secure mode is detected as OFF")
for part in part_list:
msg = "STB: %s verified" % part
if not msg in data:
self.assertTrue(False, "OPAL: %s is not verified" % part)
self.assertTrue(False, "OPAL-SB: %s is not verified" % part)

def verify_dt_sb(self):
c = self.cv_SYSTEM.sys_get_ipmi_console()
Expand Down Expand Up @@ -122,6 +140,8 @@ def setUp(self):
super(UnSignedPNOR, self).setUp()

def runTest(self):
if not self.pnor:
self.skipTest("Un-signed/improper signed PNOR image not provided")
PNORFLASH.pnor = self.pnor
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
super(UnSignedPNOR, self).runTest()
Expand All @@ -148,13 +168,42 @@ def setUp(self):
super(SignedPNOR, self).setUp()

def runTest(self):
if not self.pnor:
self.skipTest("signed PNOR image not provided")
PNORFLASH.pnor = self.pnor
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
super(SignedPNOR, self).runTest()
self.verify_boot_pass()
self.verify_dt_sb()
self.verify_opal_sb()


class SignedToPNOR(SecureBoot, PNORFLASH):
'''
Secure boot IPL test: Ensure successful boot with properly
signed to PNOR(To match the keys which are got replaced after
KeyTransitionPNOR flash test).
SB Mode | sign mode | Boot result
----------------------------------
ON | Signed | Pass
OFF | Signed | Pass
'''
def setUp(self):
conf = OpTestConfiguration.conf
self.pnor = conf.args.signed_to_pnor
super(SignedToPNOR, self).setUp()

def runTest(self):
if not self.pnor:
self.skipTest("signed PNOR image not provided")
PNORFLASH.pnor = self.pnor
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
super(SignedToPNOR, self).runTest()
self.verify_boot_pass()
self.verify_dt_sb()
self.verify_opal_sb()


class KeyTransitionPNOR(SecureBoot, PNORFLASH):
'''
Secure boot key transition test: Ensure successful key transition in SEEPROM
Expand All @@ -173,6 +222,8 @@ def setUp(self):
def runTest(self):
if not self.securemode:
return
if not self.kt_pnor:
self.skipTest("No key transition PNOR image is provided")
console = self.cv_SYSTEM.sys_get_ipmi_console()
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
PNORFLASH.pnor = self.kt_pnor
Expand All @@ -187,10 +238,47 @@ def runTest(self):
print "set state, going to off"
self.cv_SYSTEM.goto_state(OpSystemState.OFF)

class OPALContainerTest(SecureBoot, OpalLidsFLASH):
'''
System having Signed PNOR(either production or developement mode)
Flash signed containers with wrong keys
Secureboot verify should fail and boot should abort
'''
def setUp(self):
conf = OpTestConfiguration.conf
self.skiboot = None
self.skiroot_kernel = None
self.skiroot_initramfs = None
self.test_containers = conf.args.test_container
super(OPALContainerTest, self).setUp()

def runTest(self):
test_list = []
if not self.test_containers:
self.skipTest("No test containers provided")
known_part_list = ["BOOTKERNEL","CAPP", "IMA_CATALOG", "VERSION"]
# sort list with known order list
for item in known_part_list:
for pair in self.test_containers:
if item in pair[0]:
test_list.append(pair)
for container in test_list:
OpalLidsFLASH.flash_part_list = [container]
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
super(OPALContainerTest, self).runTest()
if self.securemode:
self.wait_for_secureboot_enforce()
self.cv_SYSTEM.set_state(OpSystemState.UNKNOWN)
self.cv_SYSTEM.goto_state(OpSystemState.OFF)
else:
self.cv_SYSTEM.goto_state(OpSystemState.PETITBOOT)

def secureboot_suite():
s = unittest.TestSuite()
s.addTest(UnSignedPNOR())
s.addTest(SignedPNOR())
s.addTest(KeyTransitionPNOR())
s.addTest(OPALContainerTest())
s.addTest(SignedPNOR())
s.addTest(KeyTransitionPNOR())
s.addTest(SignedToPNOR())
return s
Loading

0 comments on commit 828c53c

Please sign in to comment.