Merge ~danfuhry/ubuntu/+source/tpm2-pkcs11:backport-der-encoding-patch into ubuntu/+source/tpm2-pkcs11:ubuntu/devel

Proposed by Dan Fuhry
Status: Rejected
Rejected by: Robie Basak
Proposed branch: ~danfuhry/ubuntu/+source/tpm2-pkcs11:backport-der-encoding-patch
Merge into: ubuntu/+source/tpm2-pkcs11:ubuntu/devel
Diff against target: 215 lines (+193/-0)
3 files modified
debian/changelog (+7/-0)
debian/patches/do-not-re-encode-the-signed-data-when-importing.patch (+185/-0)
debian/patches/series (+1/-0)
Reviewer Review Type Date Requested Status
Ubuntu Sponsors Pending
git-ubuntu import Pending
Review via email: mp+437163@code.launchpad.net

Commit message

Backport upstream commit: [dbd7704d74ee] tpm2_ptool: do not re-encode the signed data when importing a certificate

Patch source: https://github.com/tpm2-software/tpm2-pkcs11/commit/dbd7704d74eeeb56ad116c073fdeb0a79be7460d.patch

Patch author: Nicolas Iooss <email address hidden>

Signed-Off-By: Dan Fuhry <email address hidden>

Description of the change

This is backport of a patch which fixes a rather serious certificate importation bug, which results in the signature being invalidated and/or the certificate being unusable when imported with `tpm2_ptool`.

To post a comment you must log in.
Revision history for this message
Robie Basak (racb) wrote :

Thank you for contributing this and helping to make Ubuntu better.

For the Ubuntu development release, it looks like this fix is incorporated into 1.9.0-0.1 and needs merging into Ubuntu, which would be preferable to a cherry-pick of the fix.

If you need the fix backported to a stable release in Ubuntu, please follow https://wiki.ubuntu.com/StableReleaseUpdates#Procedure

Revision history for this message
Robie Basak (racb) wrote :

This MP is unsuitable for the development release because it should be a merge of 1.9.0-0.1 instead, and unsuitable for Jammy because it targets the wrong branch, so I'm marking it as Rejected.

However, once you've followed the SRU steps to prepare an appropriate bug, you can resubmit nearly exactly this branch but against pkg/ubuntu/jammy-devel instead if you wish. Please modify the changelog to close the bug (that you will need to create), and the package version string would need to be 1.7.0-1ubuntu1.22.04.1 to avoid collisions with the package versions Kinetic, Lunar and Mantic. We'd also expect to have the same change submitted to Lunar to avoid users regressing in behaviour if they upgrade from Jammy to Lunar.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Unmerged commits

6a9d857... by Dan Fuhry

Backport upstream pull request #729: "Do not re-encode the signed data..."

Patch source: https://github.com/tpm2-software/tpm2-pkcs11/commit/dbd7704d74eeeb56ad116c073fdeb0a79be7460d.patch

Patch author: Nicolas Iooss <email address hidden>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index b3eb916..e244672 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,10 @@
6+tpm2-pkcs11 (1.7.0-2ubuntu1) jammy; urgency=medium
7+
8+ * Do not re-encode the signed data when importing a certificate (#729,
9+ upstream commit dbd7704d74eeeb56ad116c073fdeb0a79be7460d)
10+
11+ -- Dan Fuhry <dan@fuhry.com> Fri, 10 Feb 2021 17:55:50 -0500
12+
13 tpm2-pkcs11 (1.7.0-1ubuntu1) jammy; urgency=medium
14
15 * Do not build with Werror, many deprecation warnings from openssl v3
16diff --git a/debian/patches/do-not-re-encode-the-signed-data-when-importing.patch b/debian/patches/do-not-re-encode-the-signed-data-when-importing.patch
17new file mode 100644
18index 0000000..48e3fc0
19--- /dev/null
20+++ b/debian/patches/do-not-re-encode-the-signed-data-when-importing.patch
21@@ -0,0 +1,185 @@
22+From dbd7704d74eeeb56ad116c073fdeb0a79be7460d Mon Sep 17 00:00:00 2001
23+From: Nicolas Iooss <nicolas.iooss@ledger.fr>
24+Date: Thu, 23 Sep 2021 21:34:03 +0200
25+Subject: [PATCH] tpm2_ptool: do not re-encode the signed data when importing a
26+ certificate
27+
28+When using `tpm2_ptool addcert`, several users experienced issues
29+because the signed data of the certificate was re-encoded when being
30+added to the database. More precisely, the encoded certificate data is
31+encoded using a BER encoder which encodes booleans using 1 of True (cf.
32+https://github.com/etingof/pyasn1/blob/v0.4.8/pyasn1/codec/ber/encoder.py#L164
33+). But in DER, the encoding of "True" is 0xff, and changing the signed
34+data made the signature of the certificate no longer valid.
35+
36+To fix this issue:
37+
38+- Directly use the result of `pem.readPemFromFile(f)` in attribute
39+ `CKA_VALUE`: this is directly the encoded form of the certificate.
40+- Remove `pyasn1.codec.ber`, as this encoder is no longer used.
41+- Rename the DER decoder from `decoder` to `derdecoder` and the encoder
42+ from `derenc` to `derencoder`, to make the code easier to read.
43+
44+While at it:
45+
46+- Reindent the code to 4-space indentation
47+- Use `hashlib.sha1(bercert).digest()` directly to compute a SHA1
48+ digest, instead of using `m.update()`.
49+
50+Fixes: https://github.com/tpm2-software/tpm2-pkcs11/issues/700
51+Signed-off-by: Nicolas Iooss <nicolas.iooss@ledger.fr>
52+---
53+ tools/tpm2_pkcs11/utils.py | 126 ++++++++++++++++++-------------------
54+ 1 file changed, 60 insertions(+), 66 deletions(-)
55+
56+diff --git a/tools/tpm2_pkcs11/utils.py b/tools/tpm2_pkcs11/utils.py
57+index b803f4c2..91eab9ad 100644
58+--- a/tools/tpm2_pkcs11/utils.py
59++++ b/tools/tpm2_pkcs11/utils.py
60+@@ -15,9 +15,7 @@
61+ from cryptography.hazmat.primitives import hashes
62+
63+ from pyasn1_modules import pem, rfc2459
64+-from pyasn1.codec.der import decoder
65+-from pyasn1.codec.ber import encoder as berenc
66+-from pyasn1.codec.der import encoder as derenc
67++from pyasn1.codec.der import decoder as derdecoder, encoder as derencoder
68+ from pyasn1.type import namedtype, tag, univ
69+
70+ from .pkcs11t import * # noqa
71+@@ -247,68 +245,64 @@ def asn1_format_ec_point_uncompressed(x, y):
72+ return s
73+
74+ def pemcert_to_attrs(certpath):
75+- # rather than use pycryptography x509 parser, which gives native type access to certificate
76+- # fields use pyASN1 to get raw ASN1 encoded values for the fields as the spec requires them
77+- with open(certpath, "r") as f:
78+- substrate = pem.readPemFromFile(f)
79+- cert = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())[0]
80+-
81+- c = cert['tbsCertificate']
82+-
83+- # print(cert.prettyPrint())
84+-
85+- h = binascii.hexlify
86+- b = berenc.encode
87+- d = derenc.encode
88+-
89+- bercert = b(cert)
90+- hexbercert = h(bercert).decode()
91+-
92+- # the CKA_CHECKSUM attrs is the first 3 bytes of a sha1hash
93+- m = hashlib.sha1()
94+- m.update(bercert)
95+- bercertchecksum = m.digest()[0:3]
96+- hexbercertchecksum = h(bercertchecksum).decode()
97+-
98+- subj = c['subject']
99+- hexsubj = h(d(str2bytes(subj))).decode()
100+-
101+- issuer = c['issuer']
102+- hexissuer = h(d(str2bytes(issuer))).decode()
103+-
104+- serial = c['serialNumber']
105+- hexserial = h(d(str2bytes(serial))).decode()
106+-
107+- return {
108+- # The attrs of this attribute is derived by taking the first 3 bytes of the CKA_VALUE
109+- # field.
110+- CKA_CHECK_VALUE: hexbercertchecksum,
111+- # Start date for the certificate (default empty)
112+- CKA_START_DATE : "",
113+- # End date for the certificate (default empty)
114+- CKA_END_DATE : "",
115+- # DER-encoding of the SubjectPublicKeyInfo for the public key
116+- # contained in this certificate (default empty)
117+- CKA_PUBLIC_KEY_INFO : "",
118+- # DER encoded subject
119+- CKA_SUBJECT : hexsubj,
120+- # DER encoding of issuer
121+- CKA_ISSUER : hexissuer,
122+- # DER encoding of the cert serial
123+- CKA_SERIAL_NUMBER : hexserial,
124+- # BER encoding of the certificate
125+- CKA_VALUE : hexbercert,
126+- # RFC2279 string to URL where cert can be found, default empty
127+- CKA_URL : '',
128+- # hash of pub key subj, default empty
129+- CKA_HASH_OF_SUBJECT_PUBLIC_KEY : '',
130+- # Hash of pub key, default empty
131+- CKA_HASH_OF_ISSUER_PUBLIC_KEY : '',
132+- # Java security domain, default CK_SECURITY_DOMAIN_UNSPECIFIED
133+- CKA_JAVA_MIDP_SECURITY_DOMAIN : CK_SECURITY_DOMAIN_UNSPECIFIED,
134+- # Name hash algorithm, defaults to SHA1
135+- CKA_NAME_HASH_ALGORITHM : CKM_SHA_1
136+- }
137++ # rather than using pycryptography x509 parser, which gives native type access to certificate
138++ # fields use pyASN1 to get raw ASN1 encoded values for the fields as the spec requires them
139++ with open(certpath, "r") as f:
140++ bercert = pem.readPemFromFile(f)
141++
142++ cert = derdecoder.decode(bercert, asn1Spec=rfc2459.Certificate())[0]
143++ c = cert['tbsCertificate']
144++
145++ # print(cert.prettyPrint())
146++
147++ h = binascii.hexlify
148++ d = derencoder.encode
149++
150++ hexbercert = h(bercert).decode()
151++
152++ # the CKA_CHECKSUM attrs is the first 3 bytes of a sha1hash
153++ bercertchecksum = hashlib.sha1(bercert).digest()[0:3]
154++ hexbercertchecksum = h(bercertchecksum).decode()
155++
156++ subj = c['subject']
157++ hexsubj = h(d(str2bytes(subj))).decode()
158++
159++ issuer = c['issuer']
160++ hexissuer = h(d(str2bytes(issuer))).decode()
161++
162++ serial = c['serialNumber']
163++ hexserial = h(d(str2bytes(serial))).decode()
164++
165++ return {
166++ # The attrs of this attribute is derived by taking the first 3 bytes of the CKA_VALUE
167++ # field.
168++ CKA_CHECK_VALUE: hexbercertchecksum,
169++ # Start date for the certificate (default empty)
170++ CKA_START_DATE: "",
171++ # End date for the certificate (default empty)
172++ CKA_END_DATE: "",
173++ # DER-encoding of the SubjectPublicKeyInfo for the public key
174++ # contained in this certificate (default empty)
175++ CKA_PUBLIC_KEY_INFO: "",
176++ # DER encoded subject
177++ CKA_SUBJECT: hexsubj,
178++ # DER encoding of issuer
179++ CKA_ISSUER: hexissuer,
180++ # DER encoding of the cert serial
181++ CKA_SERIAL_NUMBER: hexserial,
182++ # BER encoding of the certificate
183++ CKA_VALUE: hexbercert,
184++ # RFC2279 string to URL where cert can be found, default empty
185++ CKA_URL: '',
186++ # hash of pub key subj, default empty
187++ CKA_HASH_OF_SUBJECT_PUBLIC_KEY: '',
188++ # Hash of pub key, default empty
189++ CKA_HASH_OF_ISSUER_PUBLIC_KEY: '',
190++ # Java security domain, default CK_SECURITY_DOMAIN_UNSPECIFIED
191++ CKA_JAVA_MIDP_SECURITY_DOMAIN: CK_SECURITY_DOMAIN_UNSPECIFIED,
192++ # Name hash algorithm, defaults to SHA1
193++ CKA_NAME_HASH_ALGORITHM: CKM_SHA_1
194++ }
195+
196+ def _pkcs11_to_str(value, prefix):
197+
198+@@ -407,7 +401,7 @@ def asn1parse_tss_key(keypath):
199+ if len(substrate) == 0:
200+ sys.exit('Did not find key in tss key file: {}'.format(keypath))
201+
202+- tss2_privkey, _ = decoder.decode(substrate, asn1Spec=TSSPrivKey())
203++ tss2_privkey, _ = derdecoder.decode(substrate, asn1Spec=TSSPrivKey())
204+
205+ return tss2_privkey
206+
207diff --git a/debian/patches/series b/debian/patches/series
208index 27c0e51..89b38b2 100644
209--- a/debian/patches/series
210+++ b/debian/patches/series
211@@ -1,3 +1,4 @@
212 remove-aclocal-git-command.patch
213 set-version-of-library.patch
214 no-werror.patch
215+do-not-re-encode-the-signed-data-when-importing.patch

Subscribers

People subscribed via source and target branches

to all changes: