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 ledgerblue.comm import getDongle
from ledgerblue.deployed import getDeployedSecret
from ledgerblue.deployed import getDeployedSecretV1, getDeployedSecretV2
from ledgerblue.hexLoader import HexLoader
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("--rootPrivateKey", help="Set the root private key")
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()
if args.appName == None:
raise Exception("Missing appName")
if args.targetId == None:
args.targetId = 0x31000001
args.targetId = 0x31000002
if args.rootPrivateKey == None:
privateKey = PrivateKey()
publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex')
@ -46,6 +47,9 @@ if args.rootPrivateKey == None:
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.deleteApp(args.appName)

View File

@ -18,12 +18,13 @@
"""
from secp256k1 import PrivateKey, PublicKey
import os
import sys
import struct
from .hexParser import IntelHexParser
from .hexLoader import HexLoader
def getDeployedSecret(dongle, masterPrivate, targetid):
def getDeployedSecretV1(dongle, masterPrivate, targetid):
testMaster = PrivateKey(bytes(masterPrivate))
testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False))
targetid = bytearray(struct.pack('>I', targetid))
@ -72,3 +73,74 @@ def getDeployedSecret(dongle, masterPrivate, targetid):
dongle.exchange(bytearray.fromhex('E053000000'))
secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex')))
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.hexParser import IntelHexParser
from ledgerblue.hexLoader import HexLoader
from ledgerblue.deployed import getDeployedSecret
from ledgerblue.deployed import getDeployedSecretV1, getDeployedSecretV2
import argparse
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("--rootPrivateKey", help="Set the root private key")
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()
if args.targetId == None:
args.targetId = 0x31000001
args.targetId = 0x31000002
if args.fileName == None:
raise Exception("Missing fileName")
if args.appName == None:
@ -57,7 +58,10 @@ if args.rootPrivateKey == None:
parser = IntelHexParser(args.fileName)
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)
if (not (args.appFlags & 2)):