@@ -190,7 +190,15 @@ def tlv_sha_to_sha(tlv):
190
190
keys .X25519 : ['256' , '512' ]
191
191
}
192
192
193
- def key_and_user_sha_to_alg_and_tlv (key , user_sha ):
193
+ ALLOWED_PURE_KEY_SHA = {
194
+ keys .Ed25519 : ['512' ]
195
+ }
196
+
197
+ ALLOWED_PURE_SIG_TLVS = [
198
+ TLV_VALUES ['ED25519' ]
199
+ ]
200
+
201
+ def key_and_user_sha_to_alg_and_tlv (key , user_sha , is_pure = False ):
194
202
"""Matches key and user requested sha to sha alogrithm and TLV name.
195
203
196
204
The returned tuple will contain hash functions and TVL name.
@@ -204,12 +212,16 @@ def key_and_user_sha_to_alg_and_tlv(key, user_sha):
204
212
205
213
# If key is not None, then we have to filter hash to only allowed
206
214
allowed = None
215
+ allowed_key_ssh = ALLOWED_PURE_KEY_SHA if is_pure else ALLOWED_KEY_SHA
207
216
try :
208
- allowed = ALLOWED_KEY_SHA [type (key )]
217
+ allowed = allowed_key_ssh [type (key )]
218
+
209
219
except KeyError :
210
220
raise click .UsageError ("Colud not find allowed hash algorithms for {}"
211
221
.format (type (key )))
212
- if user_sha == 'auto' :
222
+
223
+ # Pure enforces auto, and user selection is ignored
224
+ if user_sha == 'auto' or is_pure :
213
225
return USER_SHA_TO_ALG_AND_TLV [allowed [0 ]]
214
226
215
227
if user_sha in allowed :
@@ -447,12 +459,13 @@ def ecies_hkdf(self, enckey, plainkey):
447
459
def create (self , key , public_key_format , enckey , dependencies = None ,
448
460
sw_type = None , custom_tlvs = None , compression_tlvs = None ,
449
461
compression_type = None , encrypt_keylen = 128 , clear = False ,
450
- fixed_sig = None , pub_key = None , vector_to_sign = None , user_sha = 'auto' ):
462
+ fixed_sig = None , pub_key = None , vector_to_sign = None ,
463
+ user_sha = 'auto' , is_pure = False ):
451
464
self .enckey = enckey
452
465
453
466
# key decides on sha, then pub_key; of both are none default is used
454
467
check_key = key if key is not None else pub_key
455
- hash_algorithm , hash_tlv = key_and_user_sha_to_alg_and_tlv (check_key , user_sha )
468
+ hash_algorithm , hash_tlv = key_and_user_sha_to_alg_and_tlv (check_key , user_sha , is_pure )
456
469
457
470
# Calculate the hash of the public key
458
471
if key is not None :
@@ -592,9 +605,17 @@ def create(self, key, public_key_format, enckey, dependencies=None,
592
605
sha = hash_algorithm ()
593
606
sha .update (self .payload )
594
607
digest = sha .digest ()
595
- message = digest ;
596
608
tlv .add (hash_tlv , digest )
597
609
self .image_hash = digest
610
+ # Unless pure, we are signing digest.
611
+ message = digest
612
+
613
+ if is_pure :
614
+ # Note that when Pure signature is used, hash TLV is not present.
615
+ message = bytes (self .payload )
616
+ e = STRUCT_ENDIAN_DICT [self .endian ]
617
+ sig_pure = struct .pack (e + '?' , True )
618
+ tlv .add ('SIG_PURE' , sig_pure )
598
619
599
620
if vector_to_sign == 'payload' :
600
621
# Stop amending data to the image
@@ -786,7 +807,7 @@ def verify(imgfile, key):
786
807
version = struct .unpack ('BBHI' , b [20 :28 ])
787
808
788
809
if magic != IMAGE_MAGIC :
789
- return VerifyResult .INVALID_MAGIC , None , None
810
+ return VerifyResult .INVALID_MAGIC , None , None , None
790
811
791
812
tlv_off = header_size + img_size
792
813
tlv_info = b [tlv_off :tlv_off + TLV_INFO_SIZE ]
@@ -797,27 +818,43 @@ def verify(imgfile, key):
797
818
magic , tlv_tot = struct .unpack ('HH' , tlv_info )
798
819
799
820
if magic != TLV_INFO_MAGIC :
800
- return VerifyResult .INVALID_TLV_INFO_MAGIC , None , None
821
+ return VerifyResult .INVALID_TLV_INFO_MAGIC , None , None , None
822
+
823
+ # This is set by existence of TLV SIG_PURE
824
+ is_pure = False
801
825
802
826
prot_tlv_size = tlv_off
803
827
hash_region = b [:prot_tlv_size ]
828
+ tlv_end = tlv_off + tlv_tot
829
+ tlv_off += TLV_INFO_SIZE # skip tlv info
830
+
831
+ # First scan all TLVs in search of SIG_PURE
832
+ while tlv_off < tlv_end :
833
+ tlv = b [tlv_off :tlv_off + TLV_SIZE ]
834
+ tlv_type , _ , tlv_len = struct .unpack ('BBH' , tlv )
835
+ if tlv_type == TLV_VALUES ['SIG_PURE' ]:
836
+ is_pure = True
837
+ break
838
+ tlv_off += TLV_SIZE + tlv_len
839
+
804
840
digest = None
841
+ tlv_off = header_size + img_size
805
842
tlv_end = tlv_off + tlv_tot
806
843
tlv_off += TLV_INFO_SIZE # skip tlv info
807
844
while tlv_off < tlv_end :
808
845
tlv = b [tlv_off :tlv_off + TLV_SIZE ]
809
846
tlv_type , _ , tlv_len = struct .unpack ('BBH' , tlv )
810
847
if is_sha_tlv (tlv_type ):
811
848
if not tlv_matches_key_type (tlv_type , key ):
812
- return VerifyResult .KEY_MISMATCH , None , None
849
+ return VerifyResult .KEY_MISMATCH , None , None , None
813
850
off = tlv_off + TLV_SIZE
814
851
digest = get_digest (tlv_type , hash_region )
815
852
if digest == b [off :off + tlv_len ]:
816
853
if key is None :
817
- return VerifyResult .OK , version , digest
854
+ return VerifyResult .OK , version , digest , None
818
855
else :
819
- return VerifyResult .INVALID_HASH , None , None
820
- elif key is not None and tlv_type == TLV_VALUES [key .sig_tlv ()]:
856
+ return VerifyResult .INVALID_HASH , None , None , None
857
+ elif not is_pure and key is not None and tlv_type == TLV_VALUES [key .sig_tlv ()]:
821
858
off = tlv_off + TLV_SIZE
822
859
tlv_sig = b [off :off + tlv_len ]
823
860
payload = b [:prot_tlv_size ]
@@ -826,9 +863,18 @@ def verify(imgfile, key):
826
863
key .verify (tlv_sig , payload )
827
864
else :
828
865
key .verify_digest (tlv_sig , digest )
829
- return VerifyResult .OK , version , digest
866
+ return VerifyResult .OK , version , digest , None
867
+ except InvalidSignature :
868
+ # continue to next TLV
869
+ pass
870
+ elif is_pure and key is not None and tlv_type in ALLOWED_PURE_SIG_TLVS :
871
+ off = tlv_off + TLV_SIZE
872
+ tlv_sig = b [off :off + tlv_len ]
873
+ try :
874
+ key .verify_digest (tlv_sig , hash_region )
875
+ return VerifyResult .OK , version , None , tlv_sig
830
876
except InvalidSignature :
831
877
# continue to next TLV
832
878
pass
833
879
tlv_off += TLV_SIZE + tlv_len
834
- return VerifyResult .INVALID_SIGNATURE , None , None
880
+ return VerifyResult .INVALID_SIGNATURE , None , None , None
0 commit comments