Blame SOURCES/0004-tpm2_ptool-do-not-re-encode-the-signed-data-when-imp.patch

ad10f4
From 5bf5d6c22b9461321cec9ddeaae5795a5465bb03 Mon Sep 17 00:00:00 2001
ad10f4
From: Nicolas Iooss <nicolas.iooss@ledger.fr>
ad10f4
Date: Thu, 23 Sep 2021 21:34:03 +0200
ad10f4
Subject: [PATCH 4/6] tpm2_ptool: do not re-encode the signed data when
ad10f4
 importing a certificate
ad10f4
ad10f4
When using `tpm2_ptool addcert`, several users experienced issues
ad10f4
because the signed data of the certificate was re-encoded when being
ad10f4
added to the database. More precisely, the encoded certificate data is
ad10f4
encoded using a BER encoder which encodes booleans using 1 of True (cf.
ad10f4
https://github.com/etingof/pyasn1/blob/v0.4.8/pyasn1/codec/ber/encoder.py#L164
ad10f4
). But in DER, the encoding of "True" is 0xff, and changing the signed
ad10f4
data made the signature of the certificate no longer valid.
ad10f4
ad10f4
To fix this issue:
ad10f4
ad10f4
- Directly use the result of `pem.readPemFromFile(f)` in attribute
ad10f4
  `CKA_VALUE`: this is directly the encoded form of the certificate.
ad10f4
- Remove `pyasn1.codec.ber`, as this encoder is no longer used.
ad10f4
- Rename the DER decoder from `decoder` to `derdecoder` and the encoder
ad10f4
  from `derenc` to `derencoder`, to make the code easier to read.
ad10f4
ad10f4
While at it:
ad10f4
ad10f4
- Reindent the code to 4-space indentation
ad10f4
- Use `hashlib.sha1(bercert).digest()` directly to compute a SHA1
ad10f4
  digest, instead of using `m.update()`.
ad10f4
ad10f4
Fixes: https://github.com/tpm2-software/tpm2-pkcs11/issues/700
ad10f4
Signed-off-by: Nicolas Iooss <nicolas.iooss@ledger.fr>
ad10f4
---
ad10f4
 tools/tpm2_pkcs11/utils.py | 126 ++++++++++++++++++-------------------
ad10f4
 1 file changed, 60 insertions(+), 66 deletions(-)
ad10f4
ad10f4
diff --git a/tools/tpm2_pkcs11/utils.py b/tools/tpm2_pkcs11/utils.py
ad10f4
index b803f4c..91eab9a 100644
ad10f4
--- a/tools/tpm2_pkcs11/utils.py
ad10f4
+++ b/tools/tpm2_pkcs11/utils.py
ad10f4
@@ -15,9 +15,7 @@ from cryptography.hazmat.primitives.asymmetric import (rsa, padding)
ad10f4
 from cryptography.hazmat.primitives import hashes
ad10f4
 
ad10f4
 from pyasn1_modules import pem, rfc2459
ad10f4
-from pyasn1.codec.der import decoder
ad10f4
-from pyasn1.codec.ber import encoder as berenc
ad10f4
-from pyasn1.codec.der import encoder as derenc
ad10f4
+from pyasn1.codec.der import decoder as derdecoder, encoder as derencoder
ad10f4
 from pyasn1.type import namedtype, tag, univ
ad10f4
 
ad10f4
 from .pkcs11t import *  # noqa
ad10f4
@@ -247,68 +245,64 @@ def asn1_format_ec_point_uncompressed(x, y):
ad10f4
     return s
ad10f4
 
ad10f4
 def pemcert_to_attrs(certpath):
ad10f4
-            # rather than use pycryptography x509 parser, which gives native type access to certificate
ad10f4
-        # fields use pyASN1 to get raw ASN1 encoded values for the fields as the spec requires them
ad10f4
-        with open(certpath, "r") as f:
ad10f4
-            substrate = pem.readPemFromFile(f)
ad10f4
-            cert = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())[0]
ad10f4
-
ad10f4
-        c = cert['tbsCertificate']
ad10f4
-
ad10f4
-        # print(cert.prettyPrint())
ad10f4
-
ad10f4
-        h = binascii.hexlify
ad10f4
-        b = berenc.encode
ad10f4
-        d = derenc.encode
ad10f4
-
ad10f4
-        bercert = b(cert)
ad10f4
-        hexbercert = h(bercert).decode()
ad10f4
-
ad10f4
-        # the CKA_CHECKSUM attrs is the first 3 bytes of a sha1hash
ad10f4
-        m = hashlib.sha1()
ad10f4
-        m.update(bercert)
ad10f4
-        bercertchecksum = m.digest()[0:3]
ad10f4
-        hexbercertchecksum = h(bercertchecksum).decode()
ad10f4
-
ad10f4
-        subj = c['subject']
ad10f4
-        hexsubj = h(d(str2bytes(subj))).decode()
ad10f4
-
ad10f4
-        issuer = c['issuer']
ad10f4
-        hexissuer = h(d(str2bytes(issuer))).decode()
ad10f4
-
ad10f4
-        serial = c['serialNumber']
ad10f4
-        hexserial = h(d(str2bytes(serial))).decode()
ad10f4
-
ad10f4
-        return {
ad10f4
-            # The attrs of this attribute is derived by taking the first 3 bytes of the CKA_VALUE
ad10f4
-            # field.
ad10f4
-            CKA_CHECK_VALUE: hexbercertchecksum,
ad10f4
-            # Start date for the certificate (default empty)
ad10f4
-            CKA_START_DATE : "",
ad10f4
-            # End date for the certificate (default empty)
ad10f4
-            CKA_END_DATE : "",
ad10f4
-            # DER-encoding of the SubjectPublicKeyInfo for the public key
ad10f4
-            # contained in this certificate (default empty)
ad10f4
-            CKA_PUBLIC_KEY_INFO : "",
ad10f4
-            # DER encoded subject
ad10f4
-            CKA_SUBJECT : hexsubj,
ad10f4
-            # DER encoding of issuer
ad10f4
-            CKA_ISSUER : hexissuer,
ad10f4
-            # DER encoding of the cert serial
ad10f4
-            CKA_SERIAL_NUMBER : hexserial,
ad10f4
-            # BER encoding of the certificate
ad10f4
-            CKA_VALUE : hexbercert,
ad10f4
-            # RFC2279 string to URL where cert can be found, default empty
ad10f4
-            CKA_URL : '',
ad10f4
-            # hash of pub key subj, default empty
ad10f4
-            CKA_HASH_OF_SUBJECT_PUBLIC_KEY : '',
ad10f4
-            # Hash of pub key, default empty
ad10f4
-            CKA_HASH_OF_ISSUER_PUBLIC_KEY : '',
ad10f4
-            # Java security domain, default CK_SECURITY_DOMAIN_UNSPECIFIED
ad10f4
-            CKA_JAVA_MIDP_SECURITY_DOMAIN : CK_SECURITY_DOMAIN_UNSPECIFIED,
ad10f4
-            # Name hash algorithm, defaults to SHA1
ad10f4
-            CKA_NAME_HASH_ALGORITHM : CKM_SHA_1
ad10f4
-        }
ad10f4
+    # rather than using pycryptography x509 parser, which gives native type access to certificate
ad10f4
+    # fields use pyASN1 to get raw ASN1 encoded values for the fields as the spec requires them
ad10f4
+    with open(certpath, "r") as f:
ad10f4
+        bercert = pem.readPemFromFile(f)
ad10f4
+
ad10f4
+    cert = derdecoder.decode(bercert, asn1Spec=rfc2459.Certificate())[0]
ad10f4
+    c = cert['tbsCertificate']
ad10f4
+
ad10f4
+    # print(cert.prettyPrint())
ad10f4
+
ad10f4
+    h = binascii.hexlify
ad10f4
+    d = derencoder.encode
ad10f4
+
ad10f4
+    hexbercert = h(bercert).decode()
ad10f4
+
ad10f4
+    # the CKA_CHECKSUM attrs is the first 3 bytes of a sha1hash
ad10f4
+    bercertchecksum = hashlib.sha1(bercert).digest()[0:3]
ad10f4
+    hexbercertchecksum = h(bercertchecksum).decode()
ad10f4
+
ad10f4
+    subj = c['subject']
ad10f4
+    hexsubj = h(d(str2bytes(subj))).decode()
ad10f4
+
ad10f4
+    issuer = c['issuer']
ad10f4
+    hexissuer = h(d(str2bytes(issuer))).decode()
ad10f4
+
ad10f4
+    serial = c['serialNumber']
ad10f4
+    hexserial = h(d(str2bytes(serial))).decode()
ad10f4
+
ad10f4
+    return {
ad10f4
+        # The attrs of this attribute is derived by taking the first 3 bytes of the CKA_VALUE
ad10f4
+        # field.
ad10f4
+        CKA_CHECK_VALUE: hexbercertchecksum,
ad10f4
+        # Start date for the certificate (default empty)
ad10f4
+        CKA_START_DATE: "",
ad10f4
+        # End date for the certificate (default empty)
ad10f4
+        CKA_END_DATE: "",
ad10f4
+        # DER-encoding of the SubjectPublicKeyInfo for the public key
ad10f4
+        # contained in this certificate (default empty)
ad10f4
+        CKA_PUBLIC_KEY_INFO: "",
ad10f4
+        # DER encoded subject
ad10f4
+        CKA_SUBJECT: hexsubj,
ad10f4
+        # DER encoding of issuer
ad10f4
+        CKA_ISSUER: hexissuer,
ad10f4
+        # DER encoding of the cert serial
ad10f4
+        CKA_SERIAL_NUMBER: hexserial,
ad10f4
+        # BER encoding of the certificate
ad10f4
+        CKA_VALUE: hexbercert,
ad10f4
+        # RFC2279 string to URL where cert can be found, default empty
ad10f4
+        CKA_URL: '',
ad10f4
+        # hash of pub key subj, default empty
ad10f4
+        CKA_HASH_OF_SUBJECT_PUBLIC_KEY: '',
ad10f4
+        # Hash of pub key, default empty
ad10f4
+        CKA_HASH_OF_ISSUER_PUBLIC_KEY: '',
ad10f4
+        # Java security domain, default CK_SECURITY_DOMAIN_UNSPECIFIED
ad10f4
+        CKA_JAVA_MIDP_SECURITY_DOMAIN: CK_SECURITY_DOMAIN_UNSPECIFIED,
ad10f4
+        # Name hash algorithm, defaults to SHA1
ad10f4
+        CKA_NAME_HASH_ALGORITHM: CKM_SHA_1
ad10f4
+    }
ad10f4
 
ad10f4
 def _pkcs11_to_str(value, prefix):
ad10f4
 
ad10f4
@@ -407,7 +401,7 @@ def asn1parse_tss_key(keypath):
ad10f4
         if len(substrate) == 0:
ad10f4
             sys.exit('Did not find key in tss key file: {}'.format(keypath))
ad10f4
 
ad10f4
-        tss2_privkey, _ = decoder.decode(substrate, asn1Spec=TSSPrivKey())
ad10f4
+        tss2_privkey, _ = derdecoder.decode(substrate, asn1Spec=TSSPrivKey())
ad10f4
 
ad10f4
         return tss2_privkey
ad10f4
 
ad10f4
-- 
ad10f4
2.38.1
ad10f4