Merge ~sylvain-pineau/plainbox-provider-tpm2:clevis-jobs into plainbox-provider-tpm2:master

Proposed by Sylvain Pineau
Status: Merged
Approved by: Sylvain Pineau
Approved revision: b27dd6873f03ef4f6fef94ad1ecc41df60b9a6ca
Merged at revision: 4da022d7832047f6dc9ea72dd244dadac3942e75
Proposed branch: ~sylvain-pineau/plainbox-provider-tpm2:clevis-jobs
Merge into: plainbox-provider-tpm2:master
Diff against target: 320 lines (+284/-0)
5 files modified
bin/tpm2_capabilities.py (+190/-0)
units/clevis.pxu (+68/-0)
units/packaging.pxu (+5/-0)
units/resource.pxu (+9/-0)
units/test-plan.pxu (+12/-0)
Reviewer Review Type Date Requested Status
Jonathan Cave (community) Approve
Sylvain Pineau (community) Needs Resubmitting
Review via email: mp+404262@code.launchpad.net

Description of the change

App-level tests using clevis

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

--------------[ Running job 3 / 6. Estimated time left: unknown ]---------------
----------------------[ clevis encrypt/decrypt precheck ]-----------------------
ID: com.canonical.certification::clevis-encrypt-tpm2/precheck
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
------------------------------------------------------------------------- >8 ---
Outcome: job passed
--------------[ Running job 4 / 6. Estimated time left: unknown ]---------------
----------------[ tpm2 capabilities (algorithms and pcr banks) ]----------------
ID: com.canonical.certification::tpm2_cap
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
assymetric: ecc ecc224 ecc256 rsa rsa1024 rsa2048
symmetric: aes aes128 aes192 aes256 symcipher
hash: sha1 sha256
keyed_hash: hmac keyedhash xor
mask_generation_functions: mgf1
signature_schemes: ecdaa ecdsa ecschnorr rsapss rsassa
assymetric_encryption_scheme: ecdh oaep rsaes
key_derivation_functions: kdf1_sp800_108 kdf1_sp800_56a
aes_modes: cbc cfb ctr ecb ofb
pcr_banks: sha1 sha256
------------------------------------------------------------------------- >8 ---
Outcome: job passed
--------------[ Running job 5 / 6. Estimated time left: unknown ]---------------
-----------------------[ clevis encrypt/decrypt key rsa ]-----------------------
ID: com.canonical.certification::clevis-encrypt-tpm2/rsa
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
hello world
------------------------------------------------------------------------- >8 ---
Outcome: job passed
--------------[ Running job 6 / 6. Estimated time left: unknown ]---------------
-----------------------[ clevis encrypt/decrypt key ecc ]-----------------------
ID: com.canonical.certification::clevis-encrypt-tpm2/ecc
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
hello world
------------------------------------------------------------------------- >8 ---
Outcome: job passed
 ☑ : Hardware Manifest
 ☑ : Enumerate available system executables
 ☑ : clevis encrypt/decrypt precheck
 ☑ : tpm2 capabilities (algorithms and pcr banks)
 ☑ : clevis encrypt/decrypt key rsa
 ☑ : clevis encrypt/decrypt key ecc

Revision history for this message
Jonathan Cave (jocave) wrote :

Thanks for the effort going through the specs on this one. Looks really clean and gives us something much more like a realistic use-case.

Good to land as it. Some small improvements might be more verbosity in the tests, which might seem like overkill given they are one-liners, but I think it's reassuring to seem what might is going on.

review: Approve
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

One last commit to process larger strings (random strings) and some info msg

review: Needs Resubmitting
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

-----------------------[ clevis encrypt/decrypt key rsa ]-----------------------
ID: com.canonical.certification::clevis-encrypt-tpm2/rsa
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
+ Generate a random string
+ Encrypt and decrypt the string using the TPM
+ Compare with the original string
------------------------------------------------------------------------- >8 ---
Outcome: job passed
--------------[ Running job 6 / 6. Estimated time left: unknown ]---------------
-----------------------[ clevis encrypt/decrypt key ecc ]-----------------------
ID: com.canonical.certification::clevis-encrypt-tpm2/ecc
Category: com.canonical.certification::tpm2
... 8< -------------------------------------------------------------------------
+ Generate a random string
+ Encrypt and decrypt the string using the TPM
+ Compare with the original string
------------------------------------------------------------------------- >8 ---
Outcome: job passed

Revision history for this message
Jonathan Cave (jocave) wrote :

Nice, thank you

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/tpm2_capabilities.py b/bin/tpm2_capabilities.py
2new file mode 100755
3index 0000000..52e4e2f
4--- /dev/null
5+++ b/bin/tpm2_capabilities.py
6@@ -0,0 +1,190 @@
7+#!/usr/bin/env python3
8+
9+import yaml
10+import subprocess
11+
12+
13+# From TCG Algorithm Registry: Definition of TPM2_ALG_ID Constants
14+# https://trustedcomputinggroup.org/wp-content/uploads/TCG-_Algorithm_Registry_r1p32_pub.pdf
15+# https://github.com/tpm2-software/tpm2-tools/blob/master/lib/tpm2_alg_util.c
16+
17+TPM2_ALG_RSA = 0x0001
18+TPM2_ALG_TDES = 0x0003
19+TPM2_ALG_SHA1 = 0x0004
20+TPM2_ALG_HMAC = 0x0005
21+TPM2_ALG_AES = 0x0006
22+TPM2_ALG_MGF1 = 0x0007
23+TPM2_ALG_KEYEDHASH = 0x0008
24+TPM2_ALG_XOR = 0x000A
25+TPM2_ALG_SHA256 = 0x000B
26+TPM2_ALG_SHA384 = 0x000C
27+TPM2_ALG_SHA512 = 0x000D
28+TPM2_ALG_NULL = 0x0010
29+TPM2_ALG_SM3_256 = 0x0012
30+TPM2_ALG_SM4 = 0x0013
31+TPM2_ALG_RSASSA = 0x0014
32+TPM2_ALG_RSAES = 0x0015
33+TPM2_ALG_RSAPSS = 0x0016
34+TPM2_ALG_OAEP = 0x0017
35+TPM2_ALG_ECDSA = 0x0018
36+TPM2_ALG_ECDH = 0x0019
37+TPM2_ALG_ECDAA = 0x001A
38+TPM2_ALG_SM2 = 0x001B
39+TPM2_ALG_ECSCHNORR = 0x001C
40+TPM2_ALG_ECMQV = 0x001D
41+TPM2_ALG_KDF1_SP800_56A = 0x0020
42+TPM2_ALG_KDF2 = 0x0021
43+TPM2_ALG_KDF1_SP800_108 = 0x0022
44+TPM2_ALG_ECC = 0x0023
45+TPM2_ALG_SYMCIPHER = 0x0025
46+TPM2_ALG_CAMELLIA = 0x0026
47+TPM2_ALG_CMAC = 0x003F
48+TPM2_ALG_CTR = 0x0040
49+TPM2_ALG_SHA3_256 = 0x0027
50+TPM2_ALG_SHA3_384 = 0x0028
51+TPM2_ALG_SHA3_512 = 0x0029
52+TPM2_ALG_OFB = 0x0041
53+TPM2_ALG_CBC = 0x0042
54+TPM2_ALG_CFB = 0x0043
55+TPM2_ALG_ECB = 0x0044
56+
57+# Mandatory algorithms
58+# https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p05p_r14_pub.pdf
59+# Mandatory algorithms for PCRs are defined in Section 4.6
60+
61+# TPM2_ALG_RSA
62+# TPM2_ALG_SHA1
63+# TPM2_ALG_HMAC
64+# TPM2_ALG_AES
65+# TPM2_ALG_MGF1
66+# TPM2_ALG_KEYEDHASH
67+# TPM2_ALG_XOR
68+# TPM2_ALG_SHA256
69+# TPM2_ALG_SHA384
70+# TPM2_ALG_RSASSA
71+# TPM2_ALG_RSAES
72+# TPM2_ALG_RSAPSS
73+# TPM2_ALG_OAEP
74+# TPM2_ALG_ECDSA
75+# TPM2_ALG_ECDH
76+# TPM2_ALG_ECC
77+# TPM2_ALG_SYMCIPHER
78+
79+TPM2_CAP = {
80+ 'assymetric': set(),
81+ 'symmetric': set(),
82+ 'hash': set(),
83+ 'keyed_hash': set(),
84+ 'mask_generation_functions': set(),
85+ 'signature_schemes': set(),
86+ 'assymetric_encryption_scheme': set(),
87+ 'key_derivation_functions': set(),
88+ 'aes_modes': set(),
89+ 'pcr_banks': set(),
90+}
91+
92+try:
93+ algs_caps = subprocess.check_output(['tpm2_getcap', 'algorithms'])
94+ pcrs_caps = subprocess.check_output(['tpm2_getcap', 'pcrs'])
95+except subprocess.CalledProcessError:
96+ raise SystemExit
97+
98+algs_list = yaml.load(algs_caps, Loader=yaml.FullLoader)
99+pcrs_list = yaml.load(pcrs_caps, Loader=yaml.FullLoader)
100+
101+for alg, prop in algs_list.items():
102+ # Assymetric
103+ if prop['value'] in (TPM2_ALG_RSA, TPM2_ALG_ECC):
104+ TPM2_CAP['assymetric'].add(alg)
105+
106+ # Symmetric
107+ if prop['value'] in (
108+ TPM2_ALG_TDES, TPM2_ALG_AES, TPM2_ALG_CAMELLIA, TPM2_ALG_SYMCIPHER
109+ ):
110+ TPM2_CAP['symmetric'].add(alg)
111+
112+ # Hash
113+ if prop['value'] in (
114+ TPM2_ALG_SHA1, TPM2_ALG_SHA256, TPM2_ALG_SHA384, TPM2_ALG_SHA512,
115+ TPM2_ALG_SM3_256, TPM2_ALG_SHA3_256, TPM2_ALG_SHA3_384,
116+ TPM2_ALG_SHA3_512
117+ ):
118+ TPM2_CAP['hash'].add(alg)
119+
120+ # Keyed hash
121+ if prop['value'] in (
122+ TPM2_ALG_HMAC, TPM2_ALG_XOR, TPM2_ALG_CMAC, TPM2_ALG_KEYEDHASH
123+ ):
124+ TPM2_CAP['keyed_hash'].add(alg)
125+
126+ # Mask Generation Functions
127+ if prop['value'] in (TPM2_ALG_MGF1,):
128+ TPM2_CAP['mask_generation_functions'].add(alg)
129+
130+ # Signature Schemes
131+ if prop['value'] in (
132+ TPM2_ALG_RSASSA, TPM2_ALG_RSAPSS, TPM2_ALG_ECDSA, TPM2_ALG_ECDAA,
133+ TPM2_ALG_ECSCHNORR, TPM2_ALG_SM2, TPM2_ALG_SM4
134+ ):
135+ TPM2_CAP['signature_schemes'].add(alg)
136+
137+ # Assymetric Encryption Scheme
138+ if prop['value'] in (TPM2_ALG_OAEP, TPM2_ALG_RSAES, TPM2_ALG_ECDH):
139+ TPM2_CAP['assymetric_encryption_scheme'].add(alg)
140+
141+ # Key derivation functions
142+ if prop['value'] in (
143+ TPM2_ALG_KDF1_SP800_56A, TPM2_ALG_KDF2, TPM2_ALG_KDF1_SP800_108,
144+ TPM2_ALG_ECMQV
145+ ):
146+ TPM2_CAP['key_derivation_functions'].add(alg)
147+
148+ # AES Modes
149+ if prop['value'] in (
150+ TPM2_ALG_CTR, TPM2_ALG_OFB, TPM2_ALG_CBC, TPM2_ALG_CFB, TPM2_ALG_ECB
151+ ):
152+ TPM2_CAP['aes_modes'].add(alg)
153+
154+if 'aes' in TPM2_CAP['symmetric']:
155+ for alg_type in ('aes', 'aes128', 'aes192', 'aes256'):
156+ try:
157+ subprocess.check_call(
158+ ['tpm2_testparms', alg_type], stderr=subprocess.DEVNULL)
159+ TPM2_CAP['symmetric'].add(alg_type)
160+ except subprocess.CalledProcessError:
161+ try:
162+ TPM2_CAP['symmetric'].remove(alg_type)
163+ except KeyError:
164+ pass
165+
166+if 'ecc' in TPM2_CAP['assymetric']:
167+ for alg_type in ('ecc', 'ecc192', 'ecc224', 'ecc256', 'ecc384', 'ecc521'):
168+ try:
169+ subprocess.check_call(
170+ ['tpm2_testparms', alg_type], stderr=subprocess.DEVNULL)
171+ TPM2_CAP['assymetric'].add(alg_type)
172+ except subprocess.CalledProcessError:
173+ try:
174+ TPM2_CAP['assymetric'].remove(alg_type)
175+ except KeyError:
176+ pass
177+
178+if 'rsa' in TPM2_CAP['assymetric']:
179+ for alg_type in ('rsa', 'rsa1024', 'rsa2048', 'rsa4096'):
180+ try:
181+ subprocess.check_call(
182+ ['tpm2_testparms', alg_type], stderr=subprocess.DEVNULL)
183+ TPM2_CAP['assymetric'].add(alg_type)
184+ except subprocess.CalledProcessError:
185+ try:
186+ TPM2_CAP['assymetric'].remove(alg_type)
187+ except KeyError:
188+ pass
189+
190+for pcr in pcrs_list['selected-pcrs']:
191+ for pcr_bank, pcr_ids in pcr.items():
192+ if set(range(24)).issubset(set(pcr_ids)):
193+ TPM2_CAP['pcr_banks'].add(pcr_bank)
194+
195+for k, v in TPM2_CAP.items():
196+ print("{}: {}".format(k, ' '.join(sorted(v))))
197diff --git a/units/clevis.pxu b/units/clevis.pxu
198new file mode 100644
199index 0000000..c17ef8e
200--- /dev/null
201+++ b/units/clevis.pxu
202@@ -0,0 +1,68 @@
203+# This file is part of Checkbox.
204+#
205+# Copyright 2021 Canonical Ltd.
206+# Written by:
207+# Sylvain Pineau <sylvain.pineau@canonical.com>
208+#
209+# Checkbox is free software: you can redistribute it and/or modify
210+# it under the terms of the GNU General Public License version 3,
211+# as published by the Free Software Foundation.
212+#
213+# Checkbox is distributed in the hope that it will be useful,
214+# but WITHOUT ANY WARRANTY; without even the implied warranty of
215+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
216+# GNU General Public License for more details.
217+#
218+# You should have received a copy of the GNU General Public License
219+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
220+
221+id: clevis-encrypt-tpm2/precheck
222+category_id: tpm2
223+plugin: shell
224+imports: from com.canonical.plainbox import manifest
225+requires:
226+ manifest.has_tpm2_chip == 'True'
227+ executable.name == 'clevis-encrypt-tpm2'
228+_summary: clevis encrypt/decrypt precheck
229+flags: simple
230+command: true
231+
232+id: clevis-encrypt-tpm2/rsa
233+category_id: tpm2
234+plugin: shell
235+depends: clevis-encrypt-tpm2/precheck
236+requires:
237+ 'sha256' in tpm2_cap.hash
238+ 'sha256' in tpm2_cap.pcr_banks
239+ 'rsa' in tpm2_cap.assymetric
240+estimated_duration: 30
241+_summary: clevis encrypt/decrypt key rsa
242+flags: simple fail-on-resource
243+user: root
244+command:
245+ echo "+ Generate a random string"
246+ rand=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c32768)
247+ echo "+ Encrypt and decrypt the string using the TPM"
248+ result=$(echo -n $rand | clevis-encrypt-tpm2 '{"hash": "sha256", "key":"rsa", "pcr_bank":"sha256","pcr_ids":"0,1"}' | clevis-decrypt-tpm2)
249+ echo "+ Compare with the original string"
250+ [[ $result == $rand ]]
251+
252+id: clevis-encrypt-tpm2/ecc
253+category_id: tpm2
254+plugin: shell
255+depends: clevis-encrypt-tpm2/precheck
256+requires:
257+ 'sha256' in tpm2_cap.hash
258+ 'sha256' in tpm2_cap.pcr_banks
259+ 'ecc' in tpm2_cap.assymetric
260+estimated_duration: 30
261+_summary: clevis encrypt/decrypt key ecc
262+flags: simple fail-on-resource
263+user: root
264+command:
265+ echo "+ Generate a random string"
266+ rand=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c32768)
267+ echo "+ Encrypt and decrypt the string using the TPM"
268+ result=$(echo -n $rand | clevis-encrypt-tpm2 '{"hash": "sha256", "key":"ecc", "pcr_bank":"sha256","pcr_ids":"0,1"}' | clevis-decrypt-tpm2)
269+ echo "+ Compare with the original string"
270+ [[ $result == $rand ]]
271diff --git a/units/packaging.pxu b/units/packaging.pxu
272index 8aac195..ffa20fb 100644
273--- a/units/packaging.pxu
274+++ b/units/packaging.pxu
275@@ -10,3 +10,8 @@ unit: packaging meta-data
276 os-id: ubuntu
277 os-version-id: 20.04
278 Depends: libtss2-dev
279+
280+unit: packaging meta-data
281+os-id: ubuntu
282+os-version-id: 20.04
283+Depends: clevis-tpm2
284diff --git a/units/resource.pxu b/units/resource.pxu
285index 7487095..f58571a 100644
286--- a/units/resource.pxu
287+++ b/units/resource.pxu
288@@ -36,3 +36,12 @@ command:
289 echo tpmrm: unsupported
290 echo encryptdecrypt: unsupported
291 fi
292+
293+id: tpm2_cap
294+category_id: tpm2
295+plugin: resource
296+estimated_duration: 1
297+_summary: tpm2 capabilities (algorithms and pcr banks)
298+user: root
299+command:
300+ tpm2_capabilities.py
301diff --git a/units/test-plan.pxu b/units/test-plan.pxu
302index 927a90a..f7d5eb3 100644
303--- a/units/test-plan.pxu
304+++ b/units/test-plan.pxu
305@@ -80,3 +80,15 @@ include:
306 tpm2.0_4.1.1/.*
307 mandatory_include:
308 com.canonical.plainbox::manifest
309+
310+unit: test plan
311+id: clevis-automated
312+_name:
313+ TPM 2.0 (Trusted Platform Module) Clevis encryption tests
314+_description:
315+ Clevis encryption tests
316+estimated_duration: 1m
317+include:
318+ clevis.*
319+mandatory_include:
320+ com.canonical.plainbox::manifest

Subscribers

People subscribed via source and target branches

to all changes: