Merge pull request #2179 from gavinandresen/osx_codesign
Update mac packaging tool to create code-signed .app packages
This commit is contained in:
commit
0d89669fe9
5 changed files with 199 additions and 29 deletions
|
@ -18,6 +18,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import subprocess, sys, re, os, shutil, stat, os.path
|
import subprocess, sys, re, os, shutil, stat, os.path
|
||||||
|
from string import Template
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
@ -429,12 +430,17 @@ ap = ArgumentParser(description="""Improved version of macdeployqt.
|
||||||
Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file.
|
Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file.
|
||||||
Note, that the "dist" folder will be deleted before deploying on each run.
|
Note, that the "dist" folder will be deleted before deploying on each run.
|
||||||
|
|
||||||
Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.""")
|
Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.
|
||||||
|
|
||||||
|
Also optionally signs the .app bundle; set the CODESIGNARGS environment variable to pass arguments
|
||||||
|
to the codesign tool.
|
||||||
|
E.g. CODESIGNARGS='--sign "Developer ID Application: ..." --keychain /encrypted/foo.keychain'""")
|
||||||
|
|
||||||
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
|
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
|
||||||
ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug")
|
ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug")
|
||||||
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
|
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
|
||||||
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
|
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
|
||||||
|
ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool")
|
||||||
ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used")
|
ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used")
|
||||||
ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work")
|
ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work")
|
||||||
ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace")
|
ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace")
|
||||||
|
@ -635,6 +641,15 @@ for p in config.add_resources:
|
||||||
|
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
|
|
||||||
|
if config.sign and 'CODESIGNARGS' not in os.environ:
|
||||||
|
print "You must set the CODESIGNARGS environment variable. Skipping signing."
|
||||||
|
elif config.sign:
|
||||||
|
if verbose >= 1:
|
||||||
|
print "Code-signing app bundle %s"%(target,)
|
||||||
|
subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True)
|
||||||
|
|
||||||
|
# ------------------------------------------------
|
||||||
|
|
||||||
if config.dmg is not None:
|
if config.dmg is not None:
|
||||||
def runHDIUtil(verb, image_basename, **kwargs):
|
def runHDIUtil(verb, image_basename, **kwargs):
|
||||||
hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
|
hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
|
||||||
|
@ -713,31 +728,68 @@ if config.dmg is not None:
|
||||||
if fancy.get("applications_symlink", False):
|
if fancy.get("applications_symlink", False):
|
||||||
os.symlink("/Applications", os.path.join(disk_root, "Applications"))
|
os.symlink("/Applications", os.path.join(disk_root, "Applications"))
|
||||||
|
|
||||||
finder = appscript.app("Finder")
|
# The Python appscript package broke with OSX 10.8 and isn't being fixed.
|
||||||
disk = finder.disks[disk_name]
|
# So we now build up an AppleScript string and use the osascript command
|
||||||
disk.open()
|
# to make the .dmg file pretty:
|
||||||
window = disk.container_window
|
appscript = Template( """
|
||||||
window.current_view.set(appscript.k.icon_view)
|
on run argv
|
||||||
window.toolbar_visible.set(False)
|
tell application "Finder"
|
||||||
window.statusbar_visible.set(False)
|
tell disk "$disk"
|
||||||
if fancy.has_key("window_bounds"):
|
open
|
||||||
window.bounds.set(fancy["window_bounds"])
|
set current view of container window to icon view
|
||||||
view_options = window.icon_view_options
|
set toolbar visible of container window to false
|
||||||
view_options.arrangement.set(appscript.k.not_arranged)
|
set statusbar visible of container window to false
|
||||||
if fancy.has_key("icon_size"):
|
set the bounds of container window to {$window_bounds}
|
||||||
view_options.icon_size.set(fancy["icon_size"])
|
set theViewOptions to the icon view options of container window
|
||||||
if bg_path is not None:
|
set arrangement of theViewOptions to not arranged
|
||||||
view_options.background_picture.set(disk.files[os.path.basename(bg_path)])
|
set icon size of theViewOptions to $icon_size
|
||||||
|
$background_commands
|
||||||
|
$items_positions
|
||||||
|
close -- close/reopen works around a bug...
|
||||||
|
open
|
||||||
|
update without registering applications
|
||||||
|
delay 5
|
||||||
|
eject
|
||||||
|
end tell
|
||||||
|
end tell
|
||||||
|
end run
|
||||||
|
""")
|
||||||
|
|
||||||
|
itemscript = Template('set position of item "${item}" of container window to {${position}}')
|
||||||
|
items_positions = []
|
||||||
if fancy.has_key("items_position"):
|
if fancy.has_key("items_position"):
|
||||||
for name, position in fancy["items_position"].iteritems():
|
for name, position in fancy["items_position"].iteritems():
|
||||||
window.items[name].position.set(position)
|
params = { "item" : name, "position" : ",".join([str(p) for p in position]) }
|
||||||
disk.close()
|
items_positions.append(itemscript.substitute(params))
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"disk" : "Bitcoin-Qt",
|
||||||
|
"window_bounds" : "300,300,800,620",
|
||||||
|
"icon_size" : "96",
|
||||||
|
"background_commands" : "",
|
||||||
|
"items_positions" : "\n ".join(items_positions)
|
||||||
|
}
|
||||||
|
if fancy.has_key("window_bounds"):
|
||||||
|
params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]])
|
||||||
|
if fancy.has_key("icon_size"):
|
||||||
|
params["icon_size"] = str(fancy["icon_size"])
|
||||||
if bg_path is not None:
|
if bg_path is not None:
|
||||||
subprocess.call(["SetFile", "-a", "V", bg_path])
|
# Set background file, then call SetFile to make it invisible.
|
||||||
# disk.update(registering_applications=False)
|
# (note: making it invisible first makes set background picture fail)
|
||||||
sleep(2)
|
bgscript = Template("""set background picture of theViewOptions to file "$bgpic"
|
||||||
disk.eject()
|
do shell script "SetFile -a V /Volumes/$disk/$bgpic" """)
|
||||||
|
params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]})
|
||||||
|
|
||||||
|
s = appscript.substitute(params)
|
||||||
|
if verbose >= 2:
|
||||||
|
print("Running AppleScript:")
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE)
|
||||||
|
p.communicate(input=s)
|
||||||
|
if p.returncode:
|
||||||
|
print("Error running osascript.")
|
||||||
|
|
||||||
if verbose >= 2:
|
if verbose >= 2:
|
||||||
print "+ Finalizing .dmg disk image +"
|
print "+ Finalizing .dmg disk image +"
|
||||||
|
|
||||||
|
|
|
@ -72,12 +72,7 @@
|
||||||
rm -rf bitcoin-${VERSION}-win32
|
rm -rf bitcoin-${VERSION}-win32
|
||||||
|
|
||||||
* perform Mac build
|
* perform Mac build
|
||||||
See this blog post for how Gavin set up his build environment to build the OSX
|
OSX binaries are created by Gavin Andresen on a 32-bit, OSX 10.6 machine.
|
||||||
release; note that a patched version of macdeployqt is not needed anymore, as
|
|
||||||
the required functionality and fixes are implemented directly in macdeployqtplus:
|
|
||||||
http://gavintech.blogspot.com/2011/11/deploying-bitcoin-qt-on-osx.html
|
|
||||||
Gavin also had trouble with the macports py27-appscript package; he
|
|
||||||
ended up installing a version that worked with: /usr/bin/easy_install-2.7 appscript
|
|
||||||
|
|
||||||
qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro
|
qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro
|
||||||
make
|
make
|
||||||
|
@ -88,6 +83,9 @@
|
||||||
Build output expected:
|
Build output expected:
|
||||||
Bitcoin-Qt.dmg
|
Bitcoin-Qt.dmg
|
||||||
|
|
||||||
|
* Code-sign Windows -setup.exe (in a Windows virtual machine) and
|
||||||
|
OSX Bitcoin-Qt.app (Note: only Gavin has the code-signing keys currently)
|
||||||
|
|
||||||
* upload builds to SourceForge
|
* upload builds to SourceForge
|
||||||
|
|
||||||
* create SHA256SUMS for builds, and PGP-sign it
|
* create SHA256SUMS for builds, and PGP-sign it
|
||||||
|
|
37
share/certs/BitcoinFoundation_Apple_Cert.pem
Normal file
37
share/certs/BitcoinFoundation_Apple_Cert.pem
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
Bag Attributes
|
||||||
|
friendlyName: Developer ID Application: BITCOIN FOUNDATION, INC., THE
|
||||||
|
localKeyID: 6B 9C 6C A8 A5 73 70 70 E2 57 A3 49 D8 62 FB 97 C7 A5 5D 5E
|
||||||
|
subject=/UID=PBV4GLS9J4/CN=Developer ID Application: BITCOIN FOUNDATION, INC., THE/OU=PBV4GLS9J4/O=BITCOIN FOUNDATION, INC., THE/C=US
|
||||||
|
issuer=/CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFhzCCBG+gAwIBAgIIJ0r1rumyfZAwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UE
|
||||||
|
AwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQL
|
||||||
|
DB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUg
|
||||||
|
SW5jLjELMAkGA1UEBhMCVVMwHhcNMTMwMTEwMjIzOTAxWhcNMTgwMTExMjIzOTAx
|
||||||
|
WjCBqDEaMBgGCgmSJomT8ixkAQEMClBCVjRHTFM5SjQxQDA+BgNVBAMMN0RldmVs
|
||||||
|
b3BlciBJRCBBcHBsaWNhdGlvbjogQklUQ09JTiBGT1VOREFUSU9OLCBJTkMuLCBU
|
||||||
|
SEUxEzARBgNVBAsMClBCVjRHTFM5SjQxJjAkBgNVBAoMHUJJVENPSU4gRk9VTkRB
|
||||||
|
VElPTiwgSU5DLiwgVEhFMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||||
|
ggEPADCCAQoCggEBALTd5zURuZVoJviusr119aktXksenb9IN9vq6kBbq38vxEk7
|
||||||
|
9wkKMES2XfBRh0HxcEizGzhMNy5OCXuTLMaNMihYdfwYSoBoR2foEU+6kjPUnyJ4
|
||||||
|
dQBFLJZJr5/QeQmALmYHEgZ6lwXFD2lU8t92340zeJ4y5LZw5pcEHtH9IummYDut
|
||||||
|
OGCkCGXDcjL+5nHhNScJiXHhswM+62o6XXsQiP6EWbM1CsgrGTNLtaa0U/UvVDwE
|
||||||
|
79YKklSC5Bog2LD0jBcTuveI66mFzqu++L9X9u+ZArtebwCl7BPNQ+uboYy5uV2d
|
||||||
|
zf8lpNNZLfXCFjoLe9bLICKfZ7ub9V5aC8+GhckCAwEAAaOCAeEwggHdMD4GCCsG
|
||||||
|
AQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuYXBwbGUuY29tL29j
|
||||||
|
c3AtZGV2aWQwMTAdBgNVHQ4EFgQUa5xsqKVzcHDiV6NJ2GL7l8elXV4wDAYDVR0T
|
||||||
|
AQH/BAIwADAfBgNVHSMEGDAWgBRXF+2iz9x8mKEQ4Py+hy0s8uMXVDCCAQ4GA1Ud
|
||||||
|
IASCAQUwggEBMIH+BgkqhkiG92NkBQEwgfAwKAYIKwYBBQUHAgEWHGh0dHA6Ly93
|
||||||
|
d3cuYXBwbGUuY29tL2FwcGxlY2EwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ug
|
||||||
|
b24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRh
|
||||||
|
bmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNv
|
||||||
|
bmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmlj
|
||||||
|
YXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud
|
||||||
|
JQEB/wQMMAoGCCsGAQUFBwMDMBMGCiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3
|
||||||
|
DQEBCwUAA4IBAQAfJ0BjID/1dS2aEeVyhAzPzCBjG8vm0gDf+/qfwRn3+yWeL9vS
|
||||||
|
nMdbilwM48IyQWTagjGGcojbsAd/vE4N7NhQyHInoCllNoeor1I5xx+blTaGRBK+
|
||||||
|
dDhJbbdlGCjsLnH/BczGZi5fyEJds9lUIrp1hJidRcUKO76qb/9gc6qNZpl1vH5k
|
||||||
|
lDUuJYt7YhAs+L6rTXDyqcK9maeQr0gaOPsRRAQLLwiQCorPeMTUNsbVMdMwZYJs
|
||||||
|
R+PxiAnk+nyi7rfiFvPoASAYUuI6OzYL/Fa6QU4/gYyPgic944QYVkaQBnc0vEP1
|
||||||
|
nXq6LGKwgVGcqJnkr/E2kui5gJoV5C3qll3e
|
||||||
|
-----END CERTIFICATE-----
|
37
share/certs/BitcoinFoundation_Comodo_Cert.pem
Normal file
37
share/certs/BitcoinFoundation_Comodo_Cert.pem
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
Bag Attributes
|
||||||
|
friendlyName: The Bitcoin Foundation, Inc.'s COMODO CA Limited ID
|
||||||
|
localKeyID: 8C 94 64 E3 B5 B0 41 89 5B 89 B0 57 CC 74 B9 44 E5 B2 92 66
|
||||||
|
subject=/C=US/postalCode=98104-1444/ST=WA/L=Seattle/street=Suite 300/street=71 Columbia St/O=The Bitcoin Foundation, Inc./CN=The Bitcoin Foundation, Inc.
|
||||||
|
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFeDCCBGCgAwIBAgIRAJVYMd+waOER7lUqtiz3M2IwDQYJKoZIhvcNAQEFBQAw
|
||||||
|
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||||
|
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV
|
||||||
|
BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzAxMTYwMDAwMDBaFw0x
|
||||||
|
NDAxMTYyMzU5NTlaMIG8MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTgxMDQtMTQ0
|
||||||
|
NDELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAkMCVN1aXRl
|
||||||
|
IDMwMDEXMBUGA1UECQwONzEgQ29sdW1iaWEgU3QxJTAjBgNVBAoMHFRoZSBCaXRj
|
||||||
|
b2luIEZvdW5kYXRpb24sIEluYy4xJTAjBgNVBAMMHFRoZSBCaXRjb2luIEZvdW5k
|
||||||
|
YXRpb24sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChUwLD
|
||||||
|
u/hu5aFZ/n11B27awONaaDrmHm0pamiWHb01yL4JmTBtaLCrSftF8RhCscQ8jpI0
|
||||||
|
UG1Cchmay0e3zH5o5XRs0H9C3x+SM5ozms0TWDmAYiB8aQEghsGovDk0D2nyTQeK
|
||||||
|
Q0xqyCh0m8ZPOnMnYrakHEmF6WvhLdJvI6Od4KIwbKxgN17cPFIfLVsZ7GrzmmbU
|
||||||
|
Gdi4wSQCHy5rxzvBxho8Qq/SfBl93uOMUrqOHjOUAPhNuTJG3t/MdhU8Zp24s29M
|
||||||
|
abHtYkT9W86hMjIiI8RTAR+WHKVglx9SB0cjDabXN8SZ3gME0+H++LyzlySHT8sI
|
||||||
|
ykepojZ7UBRgp9w3AgMBAAGjggGzMIIBrzAfBgNVHSMEGDAWgBQexbEsfYfaAmh8
|
||||||
|
JbwMB4Q/ts/e8TAdBgNVHQ4EFgQUfPf+ZyDWl/4LH0Y5BuJTelkRd/EwDgYDVR0P
|
||||||
|
AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJ
|
||||||
|
YIZIAYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYI
|
||||||
|
KwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEEGA1UdHwQ6
|
||||||
|
MDgwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWdu
|
||||||
|
aW5nQ0EyLmNybDByBggrBgEFBQcBAQRmMGQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9j
|
||||||
|
cnQuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWduaW5nQ0EyLmNydDAkBggrBgEF
|
||||||
|
BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCgGA1UdEQQhMB+BHWxpbmRz
|
||||||
|
YXlAYml0Y29pbmZvdW5kYXRpb24ub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAqibjo
|
||||||
|
D4HG5XSIIMCmYE5RgQBSEAJfI+EZERk1G9F83ZUWr0yNRZCw4O+RaM7xQhvJhEoD
|
||||||
|
G2kpk/q2bNOc71/VyZ6SrE1JRVUON41/Flhz4M6cP0BclTicXvh+efVwqZhIz+ws
|
||||||
|
UxF2hvC/1Xx6rqI7NYAlOYXk2MSUq3HREo+gWUPKM8em4MZZV/7XCH4QbsfxOl1J
|
||||||
|
xS6EOQmV8hfUN4KRXI5WfGUmedBxq7dM0RSJOSQl8fq2f+JjRLfjQwQucy7LDY+y
|
||||||
|
pRTsL2TdQV/DuDuI3s0NHRGznQNddoX5jqpXhSQFAAdgrhN1gGkWaaTPzr9IF2TG
|
||||||
|
qgr6PEp9tIYC+MbM
|
||||||
|
-----END CERTIFICATE-----
|
46
share/certs/PrivateKeyNotes.md
Normal file
46
share/certs/PrivateKeyNotes.md
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
Code-signing private key notes
|
||||||
|
==
|
||||||
|
|
||||||
|
The private keys for these certificates were generated on Gavin's main work machine,
|
||||||
|
following the certificate authoritys' recommendations for generating certificate
|
||||||
|
signing requests.
|
||||||
|
|
||||||
|
For OSX, the private key was generated by Keychain.app on Gavin's main work machine.
|
||||||
|
The key and certificate is in a separate, passphrase-protected keychain file that is
|
||||||
|
unlocked to sign the Bitcoin-Qt.app bundle.
|
||||||
|
|
||||||
|
For Windows, the private key was generated by Firefox running on Gavin's main work machine.
|
||||||
|
The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and
|
||||||
|
then deleted from Firefox's keystore. The exported file is used to sign the Windows setup.exe.
|
||||||
|
|
||||||
|
Threat analysis
|
||||||
|
--
|
||||||
|
|
||||||
|
Gavin is a single point of failure. He could be coerced to divulge the secret signing keys,
|
||||||
|
allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid
|
||||||
|
signature but containing a malicious binary.
|
||||||
|
|
||||||
|
Or the machine Gavin uses to sign the binaries could be compromised, either remotely or
|
||||||
|
by breaking in to his office, allowing the attacker to get the private key files and then
|
||||||
|
install a keylogger to get the passphrase that protects them.
|
||||||
|
|
||||||
|
Threat Mitigation
|
||||||
|
--
|
||||||
|
|
||||||
|
"Air gapping" the machine used to do the signing will not work, because the signing
|
||||||
|
process needs to access a timestamp server over the network. And it would not
|
||||||
|
prevent the "rubber hose cryptography" threat (coercing Gavin to sign a bad binary
|
||||||
|
or divulge the private keys).
|
||||||
|
|
||||||
|
Windows binaries are reproducibly 'gitian-built', and the setup.exe file created
|
||||||
|
by the NSIS installer system is a 7zip archive, so you could check to make sure
|
||||||
|
that the bitcoin-qt.exe file inside the installer had not been tampered with.
|
||||||
|
However, an attacker could modify the installer's code, so when the setup.exe
|
||||||
|
was run it compromised users' systems. A volunteer to write an auditing tool
|
||||||
|
that checks the setup.exe for tampering, and checks the files in it against
|
||||||
|
the list of gitian signatures, is needed.
|
||||||
|
|
||||||
|
The long-term solution is something like the 'gitian downloader' system, which
|
||||||
|
uses signatures from multiple developers to determine whether or not a binary
|
||||||
|
should be trusted. However, that just pushes the problem to "how will
|
||||||
|
non-technical users securely get the gitian downloader code to start?"
|
Loading…
Reference in a new issue