Support 1.1 deployed logic

This commit is contained in:
BTChip 2016-05-20 08:36:47 +02:00
parent f67eb96eab
commit dfe04feb59
3 changed files with 87 additions and 7 deletions

View File

@ -19,7 +19,7 @@
from secp256k1 import PrivateKey from secp256k1 import PrivateKey
from ledgerblue.comm import getDongle from ledgerblue.comm import getDongle
from ledgerblue.deployed import getDeployedSecret from ledgerblue.deployed import getDeployedSecretV1, getDeployedSecretV2
from ledgerblue.hexLoader import HexLoader from ledgerblue.hexLoader import HexLoader
import argparse import argparse
@ -31,13 +31,14 @@ parser.add_argument("--targetId", help="Set the chip target ID", type=auto_int)
parser.add_argument("--appName", help="Set the application name") parser.add_argument("--appName", help="Set the application name")
parser.add_argument("--rootPrivateKey", help="Set the root private key") parser.add_argument("--rootPrivateKey", help="Set the root private key")
parser.add_argument("--apdu", help="Display APDU log", action='store_true') parser.add_argument("--apdu", help="Display APDU log", action='store_true')
parser.add_argument("--deployLegacy", help="Use legacy deployment API", action='store_true')
args = parser.parse_args() args = parser.parse_args()
if args.appName == None: if args.appName == None:
raise Exception("Missing appName") raise Exception("Missing appName")
if args.targetId == None: if args.targetId == None:
args.targetId = 0x31000001 args.targetId = 0x31000002
if args.rootPrivateKey == None: if args.rootPrivateKey == None:
privateKey = PrivateKey() privateKey = PrivateKey()
publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex') publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex')
@ -46,6 +47,9 @@ if args.rootPrivateKey == None:
dongle = getDongle(args.apdu) dongle = getDongle(args.apdu)
secret = getDeployedSecret(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId) if args.deployLegacy:
secret = getDeployedSecretV1(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
else:
secret = getDeployedSecretV2(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
loader = HexLoader(dongle, 0xe0, True, secret) loader = HexLoader(dongle, 0xe0, True, secret)
loader.deleteApp(args.appName) loader.deleteApp(args.appName)

View File

@ -18,12 +18,13 @@
""" """
from secp256k1 import PrivateKey, PublicKey from secp256k1 import PrivateKey, PublicKey
import os
import sys import sys
import struct import struct
from .hexParser import IntelHexParser from .hexParser import IntelHexParser
from .hexLoader import HexLoader from .hexLoader import HexLoader
def getDeployedSecret(dongle, masterPrivate, targetid): def getDeployedSecretV1(dongle, masterPrivate, targetid):
testMaster = PrivateKey(bytes(masterPrivate)) testMaster = PrivateKey(bytes(masterPrivate))
testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False)) testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False))
targetid = bytearray(struct.pack('>I', targetid)) targetid = bytearray(struct.pack('>I', targetid))
@ -72,3 +73,74 @@ def getDeployedSecret(dongle, masterPrivate, targetid):
dongle.exchange(bytearray.fromhex('E053000000')) dongle.exchange(bytearray.fromhex('E053000000'))
secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex'))) secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex')))
return str(secret[0:16]) return str(secret[0:16])
def getDeployedSecretV2(dongle, masterPrivate, targetid):
testMaster = PrivateKey(bytes(masterPrivate))
testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False))
targetid = bytearray(struct.pack('>I', targetid))
# identify
apdu = bytearray([0xe0, 0x04, 0x00, 0x00]) + bytearray([len(targetid)]) + targetid
dongle.exchange(apdu)
# walk the chain
nonce = os.urandom(8)
apdu = bytearray([0xe0, 0x50, 0x00, 0x00]) + bytearray([len(nonce)]) + nonce
auth_info = dongle.exchange(apdu)
batch_signer_serial = auth_info[0:4]
deviceNonce = auth_info[4:12]
# if not found, get another pair
#if cardKey <> testMasterPublic:
# raise Exception("Invalid batch public key")
# provide the ephemeral certificate
ephemeralPrivate = PrivateKey()
ephemeralPublic = bytearray(ephemeralPrivate.pubkey.serialize(compressed=False))
print "Using ephemeral key " + str(ephemeralPublic).encode('hex')
dataToSign = bytes(bytearray([0x11]) + nonce + deviceNonce + ephemeralPublic)
signature = testMaster.ecdsa_sign(bytes(dataToSign))
signature = testMaster.ecdsa_serialize(signature)
certificate = bytearray([len(ephemeralPublic)]) + ephemeralPublic + bytearray([len(signature)]) + signature
apdu = bytearray([0xE0, 0x51, 0x80, 0x00]) + bytearray([len(certificate)]) + certificate
dongle.exchange(apdu)
# walk the device certificates to retrieve the public key to use for authentication
index = 0
last_pub_key = PublicKey(bytes(testMasterPublic), raw=True)
while True:
if index == 0:
certificate = bytearray(dongle.exchange(bytearray.fromhex('E052000000')))
elif index == 1:
certificate = bytearray(dongle.exchange(bytearray.fromhex('E052800000')))
else:
break
if len(certificate) == 0:
break
offset = 1
certificateHeader = certificate[offset : offset + certificate[offset-1]]
offset += certificate[offset-1] + 1
certificatePublicKey = certificate[offset : offset + certificate[offset-1]]
offset += certificate[offset-1] + 1
certificateSignatureArray = certificate[offset : offset + certificate[offset-1]]
certificateSignature = last_pub_key.ecdsa_deserialize(bytes(certificateSignatureArray))
# first cert contains a header field which holds the certificate's public key role
if index == 0:
certificateSignedData = bytearray([0x02]) + certificateHeader + certificatePublicKey
# Could check if the device certificate is signed by the issuer public key
# ephemeral key certificate
else:
certificateSignedData = bytearray([0x12]) + deviceNonce + nonce + certificatePublicKey
if not last_pub_key.ecdsa_verify(bytes(certificateSignedData), certificateSignature):
if index == 0:
# Not an error if loading from user key
print "Broken certificate chain - loading from user key"
else:
raise Exception("Broken certificate chain")
last_pub_key = PublicKey(bytes(certificatePublicKey), raw=True)
index = index + 1
# Commit device ECDH channel
dongle.exchange(bytearray.fromhex('E053000000'))
secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex')))
return str(secret[0:16])

View File

@ -21,7 +21,7 @@ from secp256k1 import PrivateKey
from ledgerblue.comm import getDongle from ledgerblue.comm import getDongle
from ledgerblue.hexParser import IntelHexParser from ledgerblue.hexParser import IntelHexParser
from ledgerblue.hexLoader import HexLoader from ledgerblue.hexLoader import HexLoader
from ledgerblue.deployed import getDeployedSecret from ledgerblue.deployed import getDeployedSecretV1, getDeployedSecretV2
import argparse import argparse
def auto_int(x): def auto_int(x):
@ -35,11 +35,12 @@ parser.add_argument("--appFlags", help="Set the application flags", type=auto_in
parser.add_argument("--bootAddr", help="Set the boot address", type=auto_int) parser.add_argument("--bootAddr", help="Set the boot address", type=auto_int)
parser.add_argument("--rootPrivateKey", help="Set the root private key") parser.add_argument("--rootPrivateKey", help="Set the root private key")
parser.add_argument("--apdu", help="Display APDU log", action='store_true') parser.add_argument("--apdu", help="Display APDU log", action='store_true')
parser.add_argument("--deployLegacy", help="Use legacy deployment API", action='store_true')
args = parser.parse_args() args = parser.parse_args()
if args.targetId == None: if args.targetId == None:
args.targetId = 0x31000001 args.targetId = 0x31000002
if args.fileName == None: if args.fileName == None:
raise Exception("Missing fileName") raise Exception("Missing fileName")
if args.appName == None: if args.appName == None:
@ -57,7 +58,10 @@ if args.rootPrivateKey == None:
parser = IntelHexParser(args.fileName) parser = IntelHexParser(args.fileName)
dongle = getDongle(args.apdu) dongle = getDongle(args.apdu)
secret = getDeployedSecret(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId) if args.deployLegacy:
secret = getDeployedSecretV1(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
else:
secret = getDeployedSecretV2(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
loader = HexLoader(dongle, 0xe0, True, secret) loader = HexLoader(dongle, 0xe0, True, secret)
if (not (args.appFlags & 2)): if (not (args.appFlags & 2)):