Support 1.1 deployed logic
This commit is contained in:
parent
f67eb96eab
commit
dfe04feb59
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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)):
|
||||
|
|
Loading…
Reference in New Issue