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

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