title: Python pkcs#7 x509 chain of trust with cryptography
body: <p>I'm working on a python library to process apple pay payload into usable card details. To do so I follow the official documentation <a href="https://developer.apple.com/library/archive/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html#//apple_ref/doc/uid/TP40014929" rel="nofollow noreferrer">here</a>.</p>
  <p>Everything is working perfectly except for 2 verification steps:</p>
  <h3>Step 1.c.</h3>
  <blockquote>
  <p>Ensure that there is a valid X.509 chain of trust from the signature to the root CA. Specifically, ensure that the signature was created using the private key corresponding to the leaf certificate, that the leaf certificate is signed by the intermediate CA, and that the intermediate CA is signed by the Apple Root CA - G3.</p>
  </blockquote>
  <p>Here I ended up doing the 2 last check by the following code using the cryptography lib:</p>
  <pre class="lang-py prettyprint-override"><code>from cryptography import x509
  from cryptography.hazmat.primitives import hashes
  from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
  
  def verify_root_ca_chain_of_trust(
      trusted_root_ca: x509.Certificate,
      intermediate_cert: x509.Certificate,
      leaf_cert: x509.Certificate
  ) -&gt; None:
      try:
          # verify that the intermediate CA is signed by the Apple Root CA - G3
          trusted_pub = trusted_root_ca.public_key()
          trusted_pub.verify(
              intermediate_cert.signature,
              intermediate_cert.tbs_certificate_bytes,
              ECDSA(hashes.SHA256())
          )
          # verify that the leaf certificate is signed by the intermediate CA
          trusted_intermediate_pub = intermediate_cert.public_key()
          trusted_intermediate_pub.verify(
              leaf_cert.signature,
              leaf_cert.tbs_certificate_bytes,
              ECDSA(hashes.SHA256())
          )
      except TypeError as err:
          raise CustomError('error') from err
  </code></pre>
  <p>My problem here is that I only implement 2/3 of the checks required.
  What I can't figure out how to do is:</p>
  <blockquote>
  <p>Specifically, ensure that the signature was created using the private key corresponding to the leaf certificate</p>
  </blockquote>
  <h3>Step 1.d. and 1.e.</h3>
  <blockquote>
  <p>d. For ECC (EC_v1), ensure that the signature is a valid ECDSA signature (ecdsa-with-SHA256 1.2.840.10045.4.3.2) of the concatenated values of the ephemeralPublicKey, data, transactionId, and applicationData keys.</p>
  </blockquote>
  <blockquote>
  <p>e. Inspect the CMS signing time of the signature, as defined by section 11.3 of RFC 5652. If the time signature and the transaction time differ by more than a few minutes, it's possible that the token is a replay attack.</p>
  </blockquote>
  <p>what I tried so far:</p>
  <pre class="lang-py prettyprint-override"><code>def validate_token_signature(
      trusted_cert: x509.Certificate,
      signature: str,
      payment_data: str,
      ephemeral_pub: str,
      transaction_id: str,
      application_data: str = None,
  ) -&gt; None:
      data_byte: bytes = base64.b64decode(ephemeral_pub)
      payment_data_byte: bytes = base64.b64decode(payment_data)
      transaction_id_byte: bytes = bytes.fromhex(transaction_id)
      data: bytes = data_byte + payment_data_byte + transaction_id_byte
      if application_data is not None:
          application_data_byte: bytes = base64.b64decode(application_data)
          data = data + application_data_byte
      try:
          trusted_leaf_pub = trusted_cert.public_key()
          trusted_leaf_pub.verify(base64.b64decode(signature), data, ECDSA(hashes.SHA256()))
      except InvalidSignature as err:
          print(err)
          # raise SignatureError('error') from err```
  </code></pre>
  <p>Here they do not specified which signature to verify, I presume it's the PKCS#7 but cryptography only process pkcs#7 as a list of x509 certs as stated <a href="https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#pkcs7" rel="nofollow noreferrer">here</a>:</p>
  <blockquote>
  <p>Deserialize a PEM encoded PKCS7 blob to a list of certificates. PKCS7 can contain many other types of data, including CRLs, but this function will ignore everything except certificates.</p>
  </blockquote>
  <p>Is there a way to do those checks with python cryptography or do I have to use another lib like pyopenssl or something else?</p>