@@ -579,20 +579,57 @@ impl ManifestGen for TlvGen {
579
579
}
580
580
581
581
if self . kinds . contains ( & TlvKinds :: ECDSASIG ) {
582
+ let keyhash;
583
+ let key_bytes;
584
+ let sign_algo;
585
+ let key_pair;
586
+ let keyhash_size;
587
+ let max_sig_size;
588
+
589
+ if self . kinds . contains ( & TlvKinds :: SHA384 ) {
590
+ keyhash = digest:: digest ( & digest:: SHA384 , ECDSAP384_PUB_KEY ) ;
591
+ keyhash_size = 48 ;
592
+ key_bytes = pem:: parse ( include_bytes ! ( "../../root-ec-p384-pkcs8.pem" ) . as_ref ( ) ) . unwrap ( ) ;
593
+ sign_algo = & ECDSA_P384_SHA384_ASN1_SIGNING ;
594
+ key_pair = EcdsaKeyPair :: from_pkcs8 ( sign_algo, & key_bytes. contents ) . unwrap ( ) ;
595
+ max_sig_size = 104 ; // 96 bytes for "raw" r and s + at most 8 bytes for ASN.1 encoding
596
+ } else {
597
+ keyhash = digest:: digest ( & digest:: SHA256 , ECDSA256_PUB_KEY ) ;
598
+ keyhash_size = 32 ;
599
+ key_bytes = pem:: parse ( include_bytes ! ( "../../root-ec-p256-pkcs8.pem" ) . as_ref ( ) ) . unwrap ( ) ;
600
+ sign_algo = & ECDSA_P256_SHA256_ASN1_SIGNING ;
601
+ key_pair = EcdsaKeyPair :: from_pkcs8 ( sign_algo, & key_bytes. contents ) . unwrap ( ) ;
602
+ max_sig_size = 72 ; // 64 bytes for "raw" r and s + at most 8 bytes for ASN.1 encoding
603
+ }
604
+
605
+ // ECDSA signatures are encoded as ASN.1 with the r and s values stored as signed
606
+ // integers. As such, the size can vary depending on the value of the high bits of r and
607
+ // s. The maximum size is obtained when the high bit of both r and s is '1'. To generate
608
+ // the largest possible image, the size of the TLV area was estimated assuming the
609
+ // signature has the maximal size. To obtain a TLV area size exactly equal to the
610
+ // estimated size, the signing process is repeated multiple times until a signature
611
+ // having the largest possible size is obtained. This is taking advantage of the fact
612
+ // ECDSA signing uses a randomly-generated nonce and is therefore non-deterministic.
613
+ // Theoretically, four tries should be needed on average and the probability of not
614
+ // having obtained a signature of the desired size after 100 tries is lower than 10e-12.
582
615
let rng = rand:: SystemRandom :: new ( ) ;
583
- let ( signature, keyhash, keyhash_size) = if self . kinds . contains ( & TlvKinds :: SHA384 ) {
584
- let keyhash = digest:: digest ( & digest:: SHA384 , ECDSAP384_PUB_KEY ) ;
585
- let key_bytes = pem:: parse ( include_bytes ! ( "../../root-ec-p384-pkcs8.pem" ) . as_ref ( ) ) . unwrap ( ) ;
586
- let sign_algo = & ECDSA_P384_SHA384_ASN1_SIGNING ;
587
- let key_pair = EcdsaKeyPair :: from_pkcs8 ( sign_algo, & key_bytes. contents ) . unwrap ( ) ;
588
- ( key_pair. sign ( & rng, & sig_payload) . unwrap ( ) , keyhash, 48 )
589
- } else {
590
- let keyhash = digest:: digest ( & digest:: SHA256 , ECDSA256_PUB_KEY ) ;
591
- let key_bytes = pem:: parse ( include_bytes ! ( "../../root-ec-p256-pkcs8.pem" ) . as_ref ( ) ) . unwrap ( ) ;
592
- let sign_algo = & ECDSA_P256_SHA256_ASN1_SIGNING ;
593
- let key_pair = EcdsaKeyPair :: from_pkcs8 ( sign_algo, & key_bytes. contents ) . unwrap ( ) ;
594
- ( key_pair. sign ( & rng, & sig_payload) . unwrap ( ) , keyhash, 32 )
595
- } ;
616
+ let max_tries = 100 ;
617
+ let mut signature;
618
+ let mut tries = 0 ;
619
+
620
+ loop {
621
+ signature = key_pair. sign ( & rng, & sig_payload) . unwrap ( ) ;
622
+
623
+ if signature. as_ref ( ) . len ( ) == max_sig_size {
624
+ break ;
625
+ }
626
+
627
+ tries += 1 ;
628
+
629
+ if tries >= max_tries {
630
+ panic ! ( "Failed to generate signature of correct size" ) ;
631
+ }
632
+ }
596
633
597
634
// Write public key
598
635
let keyhash_slice = keyhash. as_ref ( ) ;
@@ -781,23 +818,8 @@ impl ManifestGen for TlvGen {
781
818
let mut size_buf = & mut result[ npro_pos + 2 .. npro_pos + 4 ] ;
782
819
size_buf. write_u16 :: < LittleEndian > ( size) . unwrap ( ) ;
783
820
784
- // ECDSA is stored as an ASN.1 integer. For a 128-bit value, this maximally results in 33
785
- // bytes of storage for each of the two values. If the high bit is zero, it will take 32
786
- // bytes, if the top 8 bits are zero, it will take 31 bits, and so on. The smaller size
787
- // will occur with decreasing likelihood. We'll allow this to get a bit smaller, hopefully
788
- // allowing the tests to pass with false failures rare. For this case, we'll handle up to
789
- // the top 16 bits of both numbers being all zeros (1 in 2^32).
790
- if !Caps :: has_ecdsa ( ) {
791
- if size_estimate != result. len ( ) {
792
- panic ! ( "Incorrect size estimate: {} (actual {})" , size_estimate, result. len( ) ) ;
793
- }
794
- } else {
795
- if size_estimate < result. len ( ) || size_estimate > result. len ( ) + 6 {
796
- panic ! ( "Incorrect size estimate: {} (actual {})" , size_estimate, result. len( ) ) ;
797
- }
798
- }
799
821
if size_estimate != result. len ( ) {
800
- log :: warn !( "Size off : {} actual {}" , size_estimate, result. len( ) ) ;
822
+ panic ! ( "Incorrect size estimate : {} ( actual {}) " , size_estimate, result. len( ) ) ;
801
823
}
802
824
803
825
result
0 commit comments