-->

Extract extension id from (ASN1) mozilla.rsa file

2019-09-15 05:06发布

问题:

How do you retrieve the extension ID from the xpi file? (It is needed f.ex. for global extension installation)

In previous versions, you could get it from the install.rdf, which no longer exists in WebExtensions. http://www.di-mgt.com.au/how-mozilla-signs-addons.html describes that it is contained in the META-INF/mozilla.rsa file.

In python, there is the pyasn1 library. I could not get it to work on the first attempt:

from pyasn1.codec.der import decoder
f = open('/path/to/addon-dir/META-INF/mozilla.rsa')
decoder.decode(f)

gave

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/pyasn1/codec/ber/decoder.py", line 623, in __call__
    raise error.PyAsn1Error('Bad octet stream type')
pyasn1.error.PyAsn1Error: Bad octet stream type

回答1:

The decode method want a buffer (string), not a file object. Use:

from pyasn1.codec.der import decoder
buf = open('/path/to/addon-dir/META-INF/mozilla.rsa').read()
decoder.decode(buf)

Worked for me.

Edit:

The pyasn1_modules package includes classes that represent some common PKCS structs. You can start with something like this:

from pyasn1.codec.der import decoder as der_decoder
from pyasn1_modules import rfc5652, rfc2315, rfc5280

mozPath = "/path/to/mozilla.rsa"
buf = open(mozPath,"rb").read()
contentInfo = der_decoder.decode(buf, asn1Spec=rfc5652.ContentInfo())[0]

if contentInfo[0] != rfc2315.signedData:
    # fail...

signedData = der_decoder.decode(contentInfo[1], asn1Spec=rfc5652.SignedData())[0]

print(signedData.prettyPrint())

This produces output similar to openssl asn1parse -inform DER -in mozilla.rsa (I myself prefer pyasn1's indentation over openssl's "d=depth".)

If you want to further parse it using pyasn1 you can try something like:

for cert in signedData["certificates"]:
    subject = cert["certificate"]["tbsCertificate"]["subject"]
    for rdn in subject["rdnSequence"]:
        if rdn[0][0] == rfc5280.AttributeType("2.5.4.3"):
            cn = rdn[0][1].asOctets()[2:]          ### Not nice
            if cn != "production-signing-ca.addons.mozilla.org":
                print cn

The major problem is here is that I'm doing something kind awful to get the string in the marked line, but except for this I don't think you can get much better.

If you find out how to get the string properly please share.



回答2:

This hack worked:

openssl asn1parse -inform DER -in mozilla.rsa  | grep -A 1 commonName | grep '{' | cut -d ':' -f 4

It relies on

  • the output of asn1parse, and
  • that the only commonName with a { belongs to the id

Anything more elegant is appreciated.