3737 4 : "04877c39fd7c62237e038235e9c075dab261630f78eeb8edb92487159fffedfdf6046c6f8b881fa407c4a4ce6c28de0b19c1f4e29f1fcbc5a58ffd1432a3e0938a" ,
3838 5 : "047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45" ,
3939}
40+ KEEPKEY_BOOTLOADER_KEYS = {
41+ 1 : "04a33cec36d6d011af09e0c498d17c3ba7ab907abfbb64caba16ad9077caacd3e198a32362c32d0ef0a7269259abbbcd8a688a0c8f54a6dbc405459566cd65141d" ,
42+ 2 : "04ab291f6bd33d0e3974f27e50070be933695a0fab7b8b3654e7c9dce74f7f98fd739b1ed86eb0be26f026e4dc6519fd2884955fa174f8a783fe455ac43f944c70" ,
43+ 3 : "04a9c29f4e053b35ffd3b9a37b073188b624c07c3a92622c131edf1a2b2c712216a8c06c9ddfdcaa39b81d9a86f0459480b0277eab0e30a34f1d26b326b8995a33" ,
44+ 4 : "04f228448eaf05171ccb68a04a0724ac586b846c54c5fd0a526f9d7c3396c98dd47aef6b2faf47b54ffa8c2861c54920ce6c2aa5607c496869023724db285495c6" ,
45+ 5 : "0418a90b536e9ffb0ec320293c33754af89b145475c4d921f818e2062c92b01be526047ccfa042b4711fb5603fe6bd7980693100b71ee766d86116a3694873f314" ,
46+ }
4047
4148V2_BOOTLOADER_KEYS = [
4249 bytes .fromhex ("c2c87a49c5a3460977fbb2ec9dfe60f06bd694db8244bd4981fe3b7a26307f3f" ),
@@ -220,13 +227,29 @@ def _decode(self, obj, ctx, path):
220227 "embedded_onev2" / c .RestreamData (c .this .code , c .Optional (FirmwareOneV2 )),
221228)
222229
230+
231+ FirmwareKeepkey = c .Struct (
232+ "magic" / c .Const (b"KPKY" ),
233+ "code_length" / c .Rebuild (c .Int32ul , c .len_ (c .this .code )),
234+ "key_indexes" / c .Int8ul [V1_SIGNATURE_SLOTS ], # pylint: disable=E1136
235+ "flags" / c .BitStruct (
236+ c .Padding (7 ),
237+ "restore_storage" / c .Flag ,
238+ ),
239+ "reserved" / c .Padding (52 ),
240+ "signatures" / c .Bytes (64 )[V1_SIGNATURE_SLOTS ],
241+ "code" / c .Bytes (c .this .code_length ),
242+ c .Terminated ,
243+ )
244+
223245# fmt: on
224246
225247
226248class FirmwareFormat (Enum ):
227249 TREZOR_ONE = 1
228250 TREZOR_T = 2
229251 TREZOR_ONE_V2 = 3
252+ KEEPKEY = 4
230253
231254
232255FirmwareType = NewType ("FirmwareType" , c .Container )
@@ -243,6 +266,9 @@ def parse(data: bytes) -> ParsedFirmware:
243266 elif data [:4 ] == b"TRZF" :
244267 version = FirmwareFormat .TREZOR_ONE_V2
245268 cls = FirmwareOneV2
269+ elif data [:4 ] == b'KPKY' :
270+ version = FirmwareFormat .KEEPKEY
271+ cls = FirmwareKeepkey
246272 else :
247273 raise ValueError ("Unrecognized firmware image type" )
248274
@@ -258,7 +284,7 @@ def digest_onev1(fw: FirmwareType) -> bytes:
258284
259285
260286def check_sig_v1 (
261- digest : bytes , key_indexes : List [int ], signatures : List [bytes ]
287+ digest : bytes , key_indexes : List [int ], signatures : List [bytes ], is_keepkey : bool = False
262288) -> None :
263289 distinct_key_indexes = set (i for i in key_indexes if i != 0 )
264290 if not distinct_key_indexes :
@@ -271,15 +297,17 @@ def check_sig_v1(
271297 )
272298 )
273299
300+ bootloader_keys = KEEPKEY_BOOTLOADER_KEYS if is_keepkey else V1_BOOTLOADER_KEYS
301+
274302 for i in range (len (key_indexes )):
275303 key_idx = key_indexes [i ]
276304 signature = signatures [i ]
277305
278- if key_idx not in V1_BOOTLOADER_KEYS :
306+ if key_idx not in bootloader_keys :
279307 # unknown pubkey
280308 raise InvalidSignatureError ("Unknown key in slot {}" .format (i ))
281309
282- pubkey = bytes .fromhex (V1_BOOTLOADER_KEYS [key_idx ])[1 :]
310+ pubkey = bytes .fromhex (bootloader_keys [key_idx ])[1 :]
283311 verify = ecdsa .VerifyingKey .from_string (pubkey , curve = ecdsa .curves .SECP256k1 )
284312 try :
285313 verify .verify_digest (signature , digest )
@@ -362,6 +390,14 @@ def validate_onev1(fw: FirmwareType, allow_unsigned: bool = False) -> None:
362390 validate_onev2 (fw .embedded_onev2 , allow_unsigned )
363391
364392
393+ def validate_keepkey (fw : FirmwareType , allow_unsigned : bool = False ) -> None :
394+ try :
395+ check_sig_v1 (digest_onev1 (fw ), fw .key_indexes , fw .signatures , True )
396+ except Unsigned :
397+ if not allow_unsigned :
398+ raise
399+
400+
365401def validate_v2 (fw : FirmwareType , skip_vendor_header : bool = False ) -> None :
366402 vendor_fingerprint = _header_digest (fw .vendor_header , VendorHeader )
367403 fingerprint = digest_v2 (fw )
@@ -405,7 +441,7 @@ def validate_v2(fw: FirmwareType, skip_vendor_header: bool = False) -> None:
405441
406442
407443def digest (version : FirmwareFormat , fw : FirmwareType ) -> bytes :
408- if version == FirmwareFormat .TREZOR_ONE :
444+ if version == FirmwareFormat .TREZOR_ONE or version == FirmwareFormat . KEEPKEY :
409445 return digest_onev1 (fw )
410446 elif version == FirmwareFormat .TREZOR_ONE_V2 :
411447 return digest_onev2 (fw )
@@ -420,6 +456,8 @@ def validate(
420456) -> None :
421457 if version == FirmwareFormat .TREZOR_ONE :
422458 return validate_onev1 (fw , allow_unsigned )
459+ elif version == FirmwareFormat .KEEPKEY :
460+ return validate_keepkey (fw , allow_unsigned )
423461 elif version == FirmwareFormat .TREZOR_ONE_V2 :
424462 return validate_onev2 (fw , allow_unsigned )
425463 elif version == FirmwareFormat .TREZOR_T :
@@ -432,15 +470,19 @@ def validate(
432470
433471
434472@tools .session
435- def update (client , data ):
473+ def update (client , data , fw_version ):
436474 if client .features .bootloader_mode is False :
437475 raise RuntimeError ("Device must be in bootloader mode" )
438476
439477 resp = client .call (messages .FirmwareErase (length = len (data )))
440478
441479 # TREZORv1 method
442480 if isinstance (resp , messages .Success ):
443- resp = client .call (messages .FirmwareUpload (payload = data ))
481+ if fw_version == FirmwareFormat .KEEPKEY :
482+ data_hash = hashlib .sha256 (data ).digest ()
483+ resp = client .call (messages .FirmwareUploadKeepkey (payload = data , hash = data_hash ))
484+ else :
485+ resp = client .call (messages .FirmwareUpload (payload = data ))
444486 if isinstance (resp , messages .Success ):
445487 return
446488 else :
0 commit comments