3

I would like to parse android apk's CERT.RSA in Python. I know it can be parsed with pyOpenSSL

import OpenSSL

cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, open('CERT.RSA', 'rb').read())

cert = OpenSSL.crypto.load_pkcs7_data(type, buffer)

cert is of type 'OpenSSL.crypto.PKCS7'.

BUT right now PKCS7 object is not complete, I cannot get attributes I need, is there any alternative way to parse that file?

kkzxak47
  • 462
  • 7
  • 16
  • 1
    What attributes are you looking for? – Mapsy Jul 14 '17 at 14:03
  • I need the sha1 digest of the public key in the signature – kkzxak47 Jul 14 '17 at 14:05
  • @stovfl Compared with PKCS12, PKCS7 have few attributes and methods. I don't know if there's a way to convert it to another format so it can be parsed. [pyopenssle doc](https://pyopenssl.readthedocs.io/en/latest/api/crypto.html#pkcs7-objects) PKCS7 objects PKCS7 objects have the following methods: PKCS7.type_is_signed() FIXME PKCS7.type_is_enveloped() FIXME PKCS7.type_is_signedAndEnveloped() FIXME PKCS7.type_is_data() FIXME PKCS7.get_type_name() Get the type name of the PKCS7. – kkzxak47 Jul 16 '17 at 09:34

1 Answers1

9

Comments: I don't know if there's a way to convert it to another format so it can be parsed

You can convert PKCS#7 to PEM using openssl, PEM is readable using PyOpenSSL

openssl pkcs7 -print_certs -in sample.p7b -out sample.cer

Question: ... how can I get the sha1 digest of the public key in the signature

It's not implemented, the Pull Request stalles since 2015.
Useing the code from the Pull Request you can doit.

From: GitHub pyca/pyopenssl: implement getters for pkcs#7 certificates, crl's, and data #367

    def get_certificates(self):
        from OpenSSL.crypto import _lib, _ffi, X509
        """
        https://github.com/pyca/pyopenssl/pull/367/files#r67300900

        Returns all certificates for the PKCS7 structure, if present. Only
        objects of type ``signedData`` or ``signedAndEnvelopedData`` can embed
        certificates.

        :return: The certificates in the PKCS7, or :const:`None` if
            there are none.
        :rtype: :class:`tuple` of :class:`X509` or :const:`None`
        """
        certs = _ffi.NULL
        if self.type_is_signed():
            certs = self._pkcs7.d.sign.cert
        elif self.type_is_signedAndEnveloped():
            certs = self._pkcs7.d.signed_and_enveloped.cert

        pycerts = []
        for i in range(_lib.sk_X509_num(certs)):
            pycert = X509.__new__(X509)
            # pycert._x509 = _lib.sk_X509_value(certs, i)
            # According to comment from @ Jari Turkia
            # to prevent segfaults use '_lib.X509_dup('
            pycert._x509 = _lib.X509_dup(_lib.sk_X509_value(certs, i))
            pycerts.append(pycert)

        if not pycerts:
            return None
        return tuple(pycerts)

Usage:

pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, open('signature.der', 'rb').read())
certs = get_certificates(pkcs7)
print(certs)
for cert in certs:
    print('digest:{}'.format(cert.digest('sha256')))

Output:

(<OpenSSL.crypto.X509 object at 0xf671b62c>, <OpenSSL.crypto.X509 object at 0xf671b86c>)
digest:b'48:19:A4:2A:56:94:22:14:73:EC:2B:01:45:9E:0B:87:92:44:26:5E:57:AF:59:F5:4C:89:F3:79:83:14:11:A3'
digest:b'25:BC:AC:86:8F:51:8B:EE:47:CC:8B:A7:78:91:7E:86:09:56:19:4B:B9:C4:10:1B:DF:13:CA:A6:54:E1:F7:4C'

Tested with Python:3.4.2 - OpenSSL:17.1.0 - cryptography:1.9 - cffi:1.10.0


Use

OpenSSL.crypto.load_pkcs7_data(type, buffer)

Load pkcs7 data from the string buffer encoded with the type type.
The type type must either FILETYPE_PEM or FILETYPE_ASN1).

stovfl
  • 14,998
  • 7
  • 24
  • 51
  • My bad. Yes, the command should be this one. The return value is of type `OpenSSL.crypto.PKCS7` How can I get the sha1 digest of the public key then? – kkzxak47 Jul 15 '17 at 03:19
  • @stovfl can this be extended to show information like CN, OU, O, ST etc? Basically anything the X509Name class can handle? – securisec Jul 02 '18 at 07:51
  • @securisec: You get a X509 object. From this object you can get the "issuers"X509Name object. See: https://pyopenssl.org/en/stable/api/crypto.html#x509-objects – stovfl Jul 05 '18 at 11:42
  • 1
    Cannot do `pycert._x509 = _lib.sk_X509_value(certs, i)` as the data will be lost. Changed into `pycert._x509 = _lib.X509_dup(_lib.sk_X509_value(certs, i))`. This copies the bytes first and assigns to a new X509 cert. No more segfaults. – Jari Turkia Feb 22 '20 at 15:26