bug 1385946 Update funsize to enable both sha1 and sha384 signing formats a=catlee DONTBUILD
authorSimon Fraser <sfraser@mozilla.com>
Tue, 01 Aug 2017 14:59:25 +0100
changeset 420876 ef9a0f01e4f68214f0ff8f4631783b8a0e075a82
parent 420875 51ffb9283f0c7c00e08eb8c39b33fbee218c370d
child 420899 65d1f1440a9fd3006e2c94a811986d3df84b257d
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscatlee
bugs1385946
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1385946 Update funsize to enable both sha1 and sha384 signing formats a=catlee DONTBUILD
taskcluster/docker/funsize-balrog-submitter/nightly.pubkey
taskcluster/docker/funsize-balrog-submitter/nightly_sha1.pubkey
taskcluster/docker/funsize-balrog-submitter/nightly_sha384.pubkey
taskcluster/docker/funsize-balrog-submitter/release.pubkey
taskcluster/docker/funsize-balrog-submitter/release_sha1.pubkey
taskcluster/docker/funsize-balrog-submitter/release_sha384.pubkey
taskcluster/docker/funsize-balrog-submitter/requirements.txt
taskcluster/docker/funsize-balrog-submitter/runme.sh
taskcluster/docker/funsize-balrog-submitter/scripts/funsize-balrog-submitter.py
taskcluster/docker/funsize-update-generator/nightly.pubkey
taskcluster/docker/funsize-update-generator/nightly_sha1.pubkey
taskcluster/docker/funsize-update-generator/nightly_sha384.pubkey
taskcluster/docker/funsize-update-generator/release.pubkey
taskcluster/docker/funsize-update-generator/release_sha1.pubkey
taskcluster/docker/funsize-update-generator/release_sha384.pubkey
taskcluster/docker/funsize-update-generator/requirements.txt
taskcluster/docker/funsize-update-generator/runme.sh
taskcluster/docker/funsize-update-generator/scripts/funsize.py
deleted file mode 100644
--- a/taskcluster/docker/funsize-balrog-submitter/nightly.pubkey
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4j/IS3gWbyVVnWn4ZRnC
-Fuzb6VAaHa0I+4E504ekhVAhbKlSfBstkLbXajdjUVAJpn02zWnOaTl5KAdpDpIp
-SkdA4mK20ej3/Ij7gIt8IwaX+ArXL8mP84pxDn5BgaNADm3206Z6YQzc/TDYu529
-qkDFmLqNUVRJAhPO+qqhKHIcVGh8HUHXN6XV1qOFip+UU0M474jAGgurVmAv8Rh7
-VvM0v5KmB6V6WHwM5gwjg2yRY/o+xYIsNeSes9rpp+MOs/RnUA6LI4WZGY4YahvX
-VclIXBDgbWPYtojexIJkmYj8JIIRsh3eCsrRRe14fq7cBurp3CxBYMlDHf0RUoaq
-hQIDAQAB
------END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-balrog-submitter/nightly_sha1.pubkey
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4j/IS3gWbyVVnWn4ZRnC
+Fuzb6VAaHa0I+4E504ekhVAhbKlSfBstkLbXajdjUVAJpn02zWnOaTl5KAdpDpIp
+SkdA4mK20ej3/Ij7gIt8IwaX+ArXL8mP84pxDn5BgaNADm3206Z6YQzc/TDYu529
+qkDFmLqNUVRJAhPO+qqhKHIcVGh8HUHXN6XV1qOFip+UU0M474jAGgurVmAv8Rh7
+VvM0v5KmB6V6WHwM5gwjg2yRY/o+xYIsNeSes9rpp+MOs/RnUA6LI4WZGY4YahvX
+VclIXBDgbWPYtojexIJkmYj8JIIRsh3eCsrRRe14fq7cBurp3CxBYMlDHf0RUoaq
+hQIDAQAB
+-----END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-balrog-submitter/nightly_sha384.pubkey
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAth151NGY8PBzn0bii9Yc
+AjYHZDwP9Lj1c3owG0zLqW2kPcdp86QTAcoYunHGYFFakNG3tooZhzwkMjZ1OrXc
+ERjD6AuVSGIBdsKtKP4vLtMjDUteFN4K2+rveozcnYFZuTWEajGu8uoYsv4QgdEA
+nTBC39j0J33xlfUR+XKuxzhxNrFX+fRFWuLDJrPziMcVA/mzf0gXlhtEsfV0HYyg
+yWpHdIWww+llysD1QOQAHk94Ss8c/4BFXFxlwlLeNlB1ZqLm1LsNy0jUy9EHeO3C
+H6eqmiFEbpdjlrkJdgR1NcTzeY/Qf/nhWH6BAZrSapQycF7OSLU+rFWMQUElSPLc
+NVl7oNAAfSYLTvRjPGi+mJK3wGFQw1EpwQl+elE1oj4+sHvIVpDrLb6btpxfr1cZ
+pR4Di/hkOIymxEDWvtUhOxUXnYbDKQSDcAHKM/xR3sdIAiVtVuL4hyBwlAqkQc2j
+H+SmnCbazgnq5+dN4y5DjoOgbZQ/koE3s3bUzzMeIxaul9v4gMtGROw3PQ3OZcP0
+lgjPRhY+NeTnWMo2nGb4/eS6Cn2qFLfbEQjsj6pJJBNKfvK/gm1jXb3PgXXdf8+d
+2xTPOX8QNpSK7C0w4vYlvSpYZlsx2cznEOV6LDqP0QHUnmd/k1xWRRGiQ7gtT+BV
+Fn0h7JyTGmEdFu6l4OhS8hMCAwEAAQ==
+-----END PUBLIC KEY-----
deleted file mode 100644
--- a/taskcluster/docker/funsize-balrog-submitter/release.pubkey
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvH4r94FpQ0gvr1hhTfV9
-NUeWPJ5CN6TZRq7v/Dc4nkJ1J4IP1B3UEii34tcNKpy1nKupiZuTT6T1zQYT+z5x
-3UkDF9qQboQ8RNb/BEz/cN3on/LTEnZ7YSraRL11M6cEB8mvmJxddCEquwqccRbs
-Usp8WUB7uRv1w6Anley7N9F/LE1iLPwJasZypRnzWb3aYsJy0cMFOYy+OXVdpktn
-qYqlNIjnt84u4Nil6UXnBbIJNUVOCY8wOFClNvVpubjPkWK1gtdWy3x/hJU5RpAO
-K9cnHxq4M/I4SUWTWO3r7yweQiHG4Jyoc7sP1jkwjBkSG93sDEycfwOdOoZft3wN
-sQIDAQAB
------END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-balrog-submitter/release_sha1.pubkey
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvH4r94FpQ0gvr1hhTfV9
+NUeWPJ5CN6TZRq7v/Dc4nkJ1J4IP1B3UEii34tcNKpy1nKupiZuTT6T1zQYT+z5x
+3UkDF9qQboQ8RNb/BEz/cN3on/LTEnZ7YSraRL11M6cEB8mvmJxddCEquwqccRbs
+Usp8WUB7uRv1w6Anley7N9F/LE1iLPwJasZypRnzWb3aYsJy0cMFOYy+OXVdpktn
+qYqlNIjnt84u4Nil6UXnBbIJNUVOCY8wOFClNvVpubjPkWK1gtdWy3x/hJU5RpAO
+K9cnHxq4M/I4SUWTWO3r7yweQiHG4Jyoc7sP1jkwjBkSG93sDEycfwOdOoZft3wN
+sQIDAQAB
+-----END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-balrog-submitter/release_sha384.pubkey
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxCHbY+fP3dvaP9XVbmK6
+i4rbqo72INEWgDSYbr/DIYfCSzHC9H8pU8dyjt+Nd8OtoUZtBD1N9fP7SlrvPZSI
+ZSW4k0e9Ky5aV3Uy+ivamSvYszkhqdeP2y7MBu73XHKYONR9PnKa+ovmREwSEI+h
+1e0ebm8zvF7Ndwx0mOeZkDu9SDkDGg4aj2xrJyBBOuGVjuctMZ6l1davANI5xiJ0
+GBEU3tR1gJs1T4vLBis5mEFn9y4kgyw/HrxmRYGnZL4fLb2fTI+pNW0Twu3KWwwi
+LgLkkVrNWiHSk7YWqxjcg5IA3pQETQ17paTHoB5Mnkvuh6MkDXvRG5VgAHZAigr6
+fJMsasOUaBeos/cD1LDQEIObpetlxc0Fiu/lvUts0755otkhI+yv35+wUa6GJrsE
+CsT7c/LaFtQXg06aGXbMLDn0bE/e+nw9KWT/rE1iYXMFkzrqoTeYJ+v7/fD/ywU8
+m8l4CZmXxzd/RogMrM3xl+j4ucAAltDQyL4yLySaIT05w5U8z2zJDEXFvpFDSRfF
+K3kjLwGub7wNwaQDuh/msIUdavu4g+GNikCXAJ8AssLuYatyHoltd2tf+EIIDW3U
+zzLpymnLo3cAz3IPfXyqVB+mcLcpqbHjl3hWms6l1wGtz6S4WqdrWs/KfzS5EyDK
+r63xn1Rg/XFmR57EsFEXAZ8CAwEAAQ==
+-----END PUBLIC KEY-----
--- a/taskcluster/docker/funsize-balrog-submitter/requirements.txt
+++ b/taskcluster/docker/funsize-balrog-submitter/requirements.txt
@@ -1,1 +1,1 @@
-mar==1.2
+mar==2.1.1
--- a/taskcluster/docker/funsize-balrog-submitter/runme.sh
+++ b/taskcluster/docker/funsize-balrog-submitter/runme.sh
@@ -1,22 +1,25 @@
 #!/bin/bash
 
 set -xe
 
 test $PARENT_TASK_ARTIFACTS_URL_PREFIX
 test $BALROG_API_ROOT
-test $SIGNING_CERT
+test $SHA1_SIGNING_CERT
+test $SHA384_SIGNING_CERT
+
 
 ARTIFACTS_DIR="/home/worker/artifacts"
 mkdir -p "$ARTIFACTS_DIR"
 
 curl --location --retry 10 --retry-delay 10 -o "$ARTIFACTS_DIR/manifest.json" \
     "$PARENT_TASK_ARTIFACTS_URL_PREFIX/manifest.json"
 
 cat "$ARTIFACTS_DIR/manifest.json"
 python /home/worker/bin/funsize-balrog-submitter.py \
     --artifacts-url-prefix "$PARENT_TASK_ARTIFACTS_URL_PREFIX" \
     --manifest "$ARTIFACTS_DIR/manifest.json" \
     -a "$BALROG_API_ROOT" \
-    --signing-cert "/home/worker/keys/${SIGNING_CERT}.pubkey" \
+    --sha1-signing-cert "/home/worker/keys/${SHA1_SIGNING_CERT}.pubkey" \
+    --sha384-signing-cert "/home/worker/keys/${SHA384_SIGNING_CERT}.pubkey" \
     --verbose \
     $EXTRA_BALROG_SUBMITTER_PARAMS
--- a/taskcluster/docker/funsize-balrog-submitter/scripts/funsize-balrog-submitter.py
+++ b/taskcluster/docker/funsize-balrog-submitter/scripts/funsize-balrog-submitter.py
@@ -3,17 +3,18 @@ import site
 import os
 import logging
 import argparse
 import json
 import hashlib
 import requests
 import tempfile
 from boto.s3.connection import S3Connection
-from mardor.marfile import MarFile
+from mardor.reader import MarReader
+from mardor.signing import get_keysize
 
 site.addsitedir("/home/worker/tools/lib/python")
 
 from balrog.submitter.cli import NightlySubmitterV4, ReleaseSubmitterV4
 from util.retry import retry, retriable
 
 log = logging.getLogger(__name__)
 
@@ -42,32 +43,33 @@ def download(url, dest, mode=None):
         if bytes_downloaded != int(r.headers['content-length']):
             raise IOError('Unexpected number of bytes downloaded')
 
     if mode:
         log.debug("chmod %o %s", mode, dest)
         os.chmod(dest, mode)
 
 
-def verify_signature(mar, signature):
+def verify_signature(mar, certs):
     log.info("Checking %s signature", mar)
-    m = MarFile(mar, signature_versions=[(1, signature)])
-    m.verify_signatures()
+    with open(mar, 'rb') as mar_fh:
+        m = MarReader(mar_fh)
+        m.verify(verify_key=certs.get(m.signature_type()))
 
 
 def verify_copy_to_s3(bucket_name, aws_access_key_id, aws_secret_access_key,
-                      mar_url, mar_dest, signing_cert):
+                      mar_url, mar_dest, signing_certs):
     conn = S3Connection(aws_access_key_id, aws_secret_access_key)
     bucket = conn.get_bucket(bucket_name)
     _, dest = tempfile.mkstemp()
     log.info("Downloading %s to %s...", mar_url, dest)
     download(mar_url, dest)
     log.info("Verifying the signature...")
     if not os.getenv("MOZ_DISABLE_MAR_CERT_VERIFICATION"):
-        verify_signature(dest, signing_cert)
+        verify_signature(dest, signing_certs)
     for name in possible_names(mar_dest, 10):
         log.info("Checking if %s already exists", name)
         key = bucket.get_key(name)
         if not key:
             log.info("Uploading to %s...", name)
             key = bucket.new_key(name)
             # There is a chance for race condition here. To avoid it we check
             # the return value with replace=False. It should be not None.
@@ -107,17 +109,18 @@ def main():
     parser = argparse.ArgumentParser()
     parser.add_argument("--artifacts-url-prefix", required=True,
                         help="URL prefix for MAR")
     parser.add_argument("--manifest", required=True)
     parser.add_argument("-a", "--api-root", required=True,
                         help="Balrog API root")
     parser.add_argument("-d", "--dummy", action="store_true",
                         help="Add '-dummy' suffix to branch name")
-    parser.add_argument("--signing-cert", required=True)
+    parser.add_argument("--sha1-signing-cert", required=True)
+    parser.add_argument("--sha384-signing-cert", required=True)
     parser.add_argument("-v", "--verbose", action="store_const",
                         dest="loglevel", const=logging.DEBUG,
                         default=logging.INFO)
     parser.add_argument("--product", help="Override product name from application.ini")
     args = parser.parse_args()
     logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s",
                         level=args.loglevel)
     logging.getLogger("requests").setLevel(logging.WARNING)
@@ -136,16 +139,24 @@ def main():
         log.warn("Skipping S3 uploads...")
         uploads_enabled = False
     else:
         uploads_enabled = True
 
     manifest = json.load(open(args.manifest))
     auth = (balrog_username, balrog_password)
 
+    signing_certs = {
+        'sha1': args.sha1_signing_cert,
+        'sha384': args.sha384_signing_cert,
+    }
+
+    assert(get_keysize(open(signing_certs['sha1'], 'rb').read()) == 2048)
+    assert(get_keysize(open(signing_certs['sha384'], 'rb').read()) == 4096)
+
     for e in manifest:
         complete_info = [{
             "hash": e["to_hash"],
             "size": e["to_size"],
         }]
         partial_info = [{
             "hash": e["hash"],
             "size": e["size"],
@@ -181,20 +192,20 @@ def main():
                 appName=e["appName"], branch=e["branch"],
                 version=e["version"], platform=e["platform"],
                 locale=e["locale"]
             )
             complete_mar_dest = "{}/{}".format(dest_prefix,
                                                complete_mar_filename)
             partial_info[0]["url"] = verify_copy_to_s3(
                 s3_bucket, aws_access_key_id, aws_secret_access_key,
-                partial_mar_url, partial_mar_dest, args.signing_cert)
+                partial_mar_url, partial_mar_dest, signing_certs)
             complete_info[0]["url"] = verify_copy_to_s3(
                 s3_bucket, aws_access_key_id, aws_secret_access_key,
-                complete_mar_url, complete_mar_dest, args.signing_cert)
+                complete_mar_url, complete_mar_dest, signing_certs)
             partial_info[0]["from_buildid"] = e["from_buildid"]
             submitter = NightlySubmitterV4(api_root=args.api_root, auth=auth,
                                            dummy=args.dummy)
             productName = args.product or e["appName"]
             retry(lambda: submitter.run(
                 platform=e["platform"], buildID=e["to_buildid"],
                 productName=productName, branch=e["branch"],
                 appVersion=e["version"], locale=e["locale"],
deleted file mode 100644
--- a/taskcluster/docker/funsize-update-generator/nightly.pubkey
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4j/IS3gWbyVVnWn4ZRnC
-Fuzb6VAaHa0I+4E504ekhVAhbKlSfBstkLbXajdjUVAJpn02zWnOaTl5KAdpDpIp
-SkdA4mK20ej3/Ij7gIt8IwaX+ArXL8mP84pxDn5BgaNADm3206Z6YQzc/TDYu529
-qkDFmLqNUVRJAhPO+qqhKHIcVGh8HUHXN6XV1qOFip+UU0M474jAGgurVmAv8Rh7
-VvM0v5KmB6V6WHwM5gwjg2yRY/o+xYIsNeSes9rpp+MOs/RnUA6LI4WZGY4YahvX
-VclIXBDgbWPYtojexIJkmYj8JIIRsh3eCsrRRe14fq7cBurp3CxBYMlDHf0RUoaq
-hQIDAQAB
------END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-update-generator/nightly_sha1.pubkey
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4j/IS3gWbyVVnWn4ZRnC
+Fuzb6VAaHa0I+4E504ekhVAhbKlSfBstkLbXajdjUVAJpn02zWnOaTl5KAdpDpIp
+SkdA4mK20ej3/Ij7gIt8IwaX+ArXL8mP84pxDn5BgaNADm3206Z6YQzc/TDYu529
+qkDFmLqNUVRJAhPO+qqhKHIcVGh8HUHXN6XV1qOFip+UU0M474jAGgurVmAv8Rh7
+VvM0v5KmB6V6WHwM5gwjg2yRY/o+xYIsNeSes9rpp+MOs/RnUA6LI4WZGY4YahvX
+VclIXBDgbWPYtojexIJkmYj8JIIRsh3eCsrRRe14fq7cBurp3CxBYMlDHf0RUoaq
+hQIDAQAB
+-----END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-update-generator/nightly_sha384.pubkey
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAth151NGY8PBzn0bii9Yc
+AjYHZDwP9Lj1c3owG0zLqW2kPcdp86QTAcoYunHGYFFakNG3tooZhzwkMjZ1OrXc
+ERjD6AuVSGIBdsKtKP4vLtMjDUteFN4K2+rveozcnYFZuTWEajGu8uoYsv4QgdEA
+nTBC39j0J33xlfUR+XKuxzhxNrFX+fRFWuLDJrPziMcVA/mzf0gXlhtEsfV0HYyg
+yWpHdIWww+llysD1QOQAHk94Ss8c/4BFXFxlwlLeNlB1ZqLm1LsNy0jUy9EHeO3C
+H6eqmiFEbpdjlrkJdgR1NcTzeY/Qf/nhWH6BAZrSapQycF7OSLU+rFWMQUElSPLc
+NVl7oNAAfSYLTvRjPGi+mJK3wGFQw1EpwQl+elE1oj4+sHvIVpDrLb6btpxfr1cZ
+pR4Di/hkOIymxEDWvtUhOxUXnYbDKQSDcAHKM/xR3sdIAiVtVuL4hyBwlAqkQc2j
+H+SmnCbazgnq5+dN4y5DjoOgbZQ/koE3s3bUzzMeIxaul9v4gMtGROw3PQ3OZcP0
+lgjPRhY+NeTnWMo2nGb4/eS6Cn2qFLfbEQjsj6pJJBNKfvK/gm1jXb3PgXXdf8+d
+2xTPOX8QNpSK7C0w4vYlvSpYZlsx2cznEOV6LDqP0QHUnmd/k1xWRRGiQ7gtT+BV
+Fn0h7JyTGmEdFu6l4OhS8hMCAwEAAQ==
+-----END PUBLIC KEY-----
deleted file mode 100644
--- a/taskcluster/docker/funsize-update-generator/release.pubkey
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvH4r94FpQ0gvr1hhTfV9
-NUeWPJ5CN6TZRq7v/Dc4nkJ1J4IP1B3UEii34tcNKpy1nKupiZuTT6T1zQYT+z5x
-3UkDF9qQboQ8RNb/BEz/cN3on/LTEnZ7YSraRL11M6cEB8mvmJxddCEquwqccRbs
-Usp8WUB7uRv1w6Anley7N9F/LE1iLPwJasZypRnzWb3aYsJy0cMFOYy+OXVdpktn
-qYqlNIjnt84u4Nil6UXnBbIJNUVOCY8wOFClNvVpubjPkWK1gtdWy3x/hJU5RpAO
-K9cnHxq4M/I4SUWTWO3r7yweQiHG4Jyoc7sP1jkwjBkSG93sDEycfwOdOoZft3wN
-sQIDAQAB
------END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-update-generator/release_sha1.pubkey
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvH4r94FpQ0gvr1hhTfV9
+NUeWPJ5CN6TZRq7v/Dc4nkJ1J4IP1B3UEii34tcNKpy1nKupiZuTT6T1zQYT+z5x
+3UkDF9qQboQ8RNb/BEz/cN3on/LTEnZ7YSraRL11M6cEB8mvmJxddCEquwqccRbs
+Usp8WUB7uRv1w6Anley7N9F/LE1iLPwJasZypRnzWb3aYsJy0cMFOYy+OXVdpktn
+qYqlNIjnt84u4Nil6UXnBbIJNUVOCY8wOFClNvVpubjPkWK1gtdWy3x/hJU5RpAO
+K9cnHxq4M/I4SUWTWO3r7yweQiHG4Jyoc7sP1jkwjBkSG93sDEycfwOdOoZft3wN
+sQIDAQAB
+-----END PUBLIC KEY-----
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/funsize-update-generator/release_sha384.pubkey
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxCHbY+fP3dvaP9XVbmK6
+i4rbqo72INEWgDSYbr/DIYfCSzHC9H8pU8dyjt+Nd8OtoUZtBD1N9fP7SlrvPZSI
+ZSW4k0e9Ky5aV3Uy+ivamSvYszkhqdeP2y7MBu73XHKYONR9PnKa+ovmREwSEI+h
+1e0ebm8zvF7Ndwx0mOeZkDu9SDkDGg4aj2xrJyBBOuGVjuctMZ6l1davANI5xiJ0
+GBEU3tR1gJs1T4vLBis5mEFn9y4kgyw/HrxmRYGnZL4fLb2fTI+pNW0Twu3KWwwi
+LgLkkVrNWiHSk7YWqxjcg5IA3pQETQ17paTHoB5Mnkvuh6MkDXvRG5VgAHZAigr6
+fJMsasOUaBeos/cD1LDQEIObpetlxc0Fiu/lvUts0755otkhI+yv35+wUa6GJrsE
+CsT7c/LaFtQXg06aGXbMLDn0bE/e+nw9KWT/rE1iYXMFkzrqoTeYJ+v7/fD/ywU8
+m8l4CZmXxzd/RogMrM3xl+j4ucAAltDQyL4yLySaIT05w5U8z2zJDEXFvpFDSRfF
+K3kjLwGub7wNwaQDuh/msIUdavu4g+GNikCXAJ8AssLuYatyHoltd2tf+EIIDW3U
+zzLpymnLo3cAz3IPfXyqVB+mcLcpqbHjl3hWms6l1wGtz6S4WqdrWs/KfzS5EyDK
+r63xn1Rg/XFmR57EsFEXAZ8CAwEAAQ==
+-----END PUBLIC KEY-----
--- a/taskcluster/docker/funsize-update-generator/requirements.txt
+++ b/taskcluster/docker/funsize-update-generator/requirements.txt
@@ -1,2 +1,2 @@
-mar==1.2
+mar==2.1.1
 redo
--- a/taskcluster/docker/funsize-update-generator/runme.sh
+++ b/taskcluster/docker/funsize-update-generator/runme.sh
@@ -1,14 +1,15 @@
 #!/bin/sh
 
 set -xe
 
 test $TASK_ID
-test $SIGNING_CERT
+test $SHA1_SIGNING_CERT
+test $SHA384_SIGNING_CERT
 
 ARTIFACTS_DIR="/home/worker/artifacts"
 mkdir -p "$ARTIFACTS_DIR"
 
 curl --location --retry 10 --retry-delay 10 -o /home/worker/task.json \
     "https://queue.taskcluster.net/v1/task/$TASK_ID"
 
 # enable locale cache
@@ -16,10 +17,11 @@ export MBSDIFF_HOOK="/home/worker/bin/mb
 
 if [ ! -z $FILENAME_TEMPLATE ]; then
     EXTRA_PARAMS="--filename-template $FILENAME_TEMPLATE $EXTRA_PARAMS"
 fi
 
 /home/worker/bin/funsize.py \
     --artifacts-dir "$ARTIFACTS_DIR" \
     --task-definition /home/worker/task.json \
-    --signing-cert "/home/worker/keys/${SIGNING_CERT}.pubkey" \
+    --sha1-signing-cert "/home/worker/keys/${SHA1_SIGNING_CERT}.pubkey" \
+    --sha384-signing-cert "/home/worker/keys/${SHA384_SIGNING_CERT}.pubkey" \
     $EXTRA_PARAMS
--- a/taskcluster/docker/funsize-update-generator/scripts/funsize.py
+++ b/taskcluster/docker/funsize-update-generator/scripts/funsize.py
@@ -8,37 +8,45 @@ import json
 import logging
 import os
 import shutil
 import tempfile
 import requests
 import sh
 
 import redo
-from mardor.marfile import MarFile
+from mardor.reader import MarReader
+from mardor.signing import get_keysize
+
 
 log = logging.getLogger(__name__)
 ALLOWED_URL_PREFIXES = [
     "http://download.cdn.mozilla.net/pub/mozilla.org/firefox/nightly/",
     "http://download.cdn.mozilla.net/pub/firefox/nightly/",
     "https://mozilla-nightly-updates.s3.amazonaws.com",
     "https://queue.taskcluster.net/",
     "http://ftp.mozilla.org/",
     "http://download.mozilla.org/",
     "https://archive.mozilla.org/",
 ]
 
 DEFAULT_FILENAME_TEMPLATE = "{appName}-{branch}-{version}-{platform}-" \
                             "{locale}-{from_buildid}-{to_buildid}.partial.mar"
 
 
-def verify_signature(mar, signature):
+def verify_signature(mar, certs):
     log.info("Checking %s signature", mar)
-    m = MarFile(mar, signature_versions=[(1, signature)])
-    m.verify_signatures()
+    with open(mar, 'rb') as mar_fh:
+        m = MarReader(mar_fh)
+        m.verify(verify_key=certs.get(m.signature_type()))
+
+
+def is_lzma_compressed_mar(mar):
+    log.info("Checking %s for lzma compression", mar)
+    return MarReader(open(mar, 'rb')).compression_type() == 'xz'
 
 
 @redo.retriable()
 def download(url, dest, mode=None):
     log.debug("Downloading %s to %s", url, dest)
     r = requests.get(url)
     r.raise_for_status()
 
@@ -59,17 +67,22 @@ def download(url, dest, mode=None):
         os.chmod(dest, mode)
 
 
 def unpack(work_env, mar, dest_dir):
     os.mkdir(dest_dir)
     unwrap_cmd = sh.Command(os.path.join(work_env.workdir,
                                          "unwrap_full_update.pl"))
     log.debug("Unwrapping %s", mar)
-    out = unwrap_cmd(mar, _cwd=dest_dir, _env=work_env.env, _timeout=240,
+    env = work_env.env
+    if not is_lzma_compressed_mar(mar):
+        env['MAR_OLD_FORMAT'] = 1
+    elif 'MAR_OLD_FORMAT' in env:
+        del env['MAR_OLD_FORMAT']
+    out = unwrap_cmd(mar, _cwd=dest_dir, _env=env, _timeout=240,
                      _err_to_out=True)
     if out:
         log.debug(out)
 
 
 def find_file(directory, filename):
     log.debug("Searching for %s in %s", filename, directory)
     for root, dirs, files in os.walk(directory):
@@ -91,16 +104,20 @@ def get_option(directory, filename, sect
 
 
 def generate_partial(work_env, from_dir, to_dir, dest_mar, channel_ids,
                      version):
     log.debug("Generating partial %s", dest_mar)
     env = work_env.env
     env["MOZ_PRODUCT_VERSION"] = version
     env["MOZ_CHANNEL_ID"] = channel_ids
+    if not is_lzma_compressed_mar(dest_mar):
+        env['MAR_OLD_FORMAT'] = 1
+    elif 'MAR_OLD_FORMAT' in env:
+        del env['MAR_OLD_FORMAT']
     make_incremental_update = os.path.join(work_env.workdir,
                                            "make_incremental_update.sh")
     out = sh.bash(make_incremental_update, dest_mar, from_dir, to_dir,
                   _cwd=work_env.workdir, _env=env, _timeout=900,
                   _err_to_out=True)
     if out:
         log.debug(out)
 
@@ -161,33 +178,42 @@ def verify_allowed_url(mar):
         raise ValueError("{mar} is not in allowed URL prefixes: {p}".format(
             mar=mar, p=ALLOWED_URL_PREFIXES
         ))
 
 
 def main():
     parser = argparse.ArgumentParser()
     parser.add_argument("--artifacts-dir", required=True)
-    parser.add_argument("--signing-cert", required=True)
+    parser.add_argument("--sha1-signing-cert", required=True)
+    parser.add_argument("--sha384-signing-cert", required=True)
     parser.add_argument("--task-definition", required=True,
                         type=argparse.FileType('r'))
     parser.add_argument("--filename-template",
                         default=DEFAULT_FILENAME_TEMPLATE)
     parser.add_argument("--no-freshclam", action="store_true", default=False,
                         help="Do not refresh ClamAV DB")
     parser.add_argument("-q", "--quiet", dest="log_level",
                         action="store_const", const=logging.WARNING,
                         default=logging.DEBUG)
     args = parser.parse_args()
 
     logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s",
                         level=args.log_level)
     task = json.load(args.task_definition)
     # TODO: verify task["extra"]["funsize"]["partials"] with jsonschema
 
+    signing_certs = {
+        'sha1': args.sha1_signing_cert,
+        'sha384': args.sha384_signing_cert,
+    }
+
+    assert(get_keysize(open(signing_certs['sha1'], 'rb').read()) == 2048)
+    assert(get_keysize(open(signing_certs['sha384'], 'rb').read()) == 4096)
+
     if args.no_freshclam:
         log.info("Skipping freshclam")
     else:
         log.info("Refreshing clamav db...")
         try:
             redo.retry(lambda: sh.freshclam("--stdout", "--verbose",
                                             _timeout=300, _err_to_out=True))
             log.info("Done.")
@@ -202,17 +228,17 @@ def main():
         # TODO: run setup once
         work_env.setup()
         complete_mars = {}
         for mar_type, f in (("from", e["from_mar"]), ("to", e["to_mar"])):
             dest = os.path.join(work_env.workdir, "{}.mar".format(mar_type))
             unpack_dir = os.path.join(work_env.workdir, mar_type)
             download(f, dest)
             if not os.getenv("MOZ_DISABLE_MAR_CERT_VERIFICATION"):
-                verify_signature(dest, args.signing_cert)
+                verify_signature(dest, signing_certs)
             complete_mars["%s_size" % mar_type] = os.path.getsize(dest)
             complete_mars["%s_hash" % mar_type] = get_hash(dest)
             unpack(work_env, dest, unpack_dir)
             log.info("AV-scanning %s ...", unpack_dir)
             sh.clamscan("-r", unpack_dir, _timeout=600, _err_to_out=True)
             log.info("Done.")
 
         path = os.path.join(work_env.workdir, "to")