From 25379903ab94a22f22c2d85332b21138f2ddca2e Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 6 Sep 2024 14:33:19 +1000 Subject: [PATCH] Add support for ECDSA NIST P256 signature credentials Signed-off-by: Alistair Francis --- README.md | 17 ++++++++++++++-- src/cmdline.rs | 7 +++++++ src/convert.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/header.rs | 1 + src/main.rs | 1 + 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 950995d..514c8b1 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,11 @@ elf2tab supports adding credentials to the TBF footer of the generated TBF files. To add a hash, use one or more of these flags: `--sha256`, `--sha384`, `--sha512`. -elf2tab can also sign the TBF with a public/private RSA key pair. To generate -compatible keys: +elf2tab can also sign the TBF with a public/private key pairs. elf2tab uses +ring to do this, a range of commands to generate and prepare keys for ring can +be found at: https://gist.github.com/briansmith/2ee42439923d8e65a266994d0f70180b + +To generate compatible RSA keys: $ openssl genrsa -aes256 -out tockkey.private.pem 4096 $ openssl pkcs8 -topk8 -nocrypt -outform der -in tockkey.private.pem -out tockkey.private.pk8 @@ -84,6 +87,16 @@ Example including multiple credentials: $ elf2tab --sha256 --sha384 --sha512 --rsa4096-private tockkey.private.pk8 ... +To generate compatible ECDSA NIST P256 keys: + +Use an existing PEM private key (one that starts with `-----BEGIN PRIVATE KEY-----`) + + $ openssl pkcs8 -in priv_key.pem -topk8 -nocrypt -outform der > p256-private-key.p8 + +Then pass the keys to elf2tab: + + $ elf2tab --ecdsa-nist-p256-private p256-private-key.p8 ... + elf2tab Details --------------- diff --git a/src/cmdline.rs b/src/cmdline.rs index 87eda30..ca069eb 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -214,6 +214,13 @@ pub struct Opt { help = "Add an 4096-bit RSA signature credential using this private key" )] pub rsa4096_private_key: Option, + + #[arg( + long = "ecdsa-nist-p256-private", + id = "ecdsa-nist-p256-private-key", + help = "Add an ECDSA NIST P256 signature credential using this private key" + )] + pub ecdsa_nist_p256_private_key: Option, } mod test { diff --git a/src/convert.rs b/src/convert.rs index b6fb106..1775321 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -141,6 +141,7 @@ pub fn elf_to_tbf( sha384: bool, sha512: bool, rsa4096_private_key: Option, + ecdsa_nist_p256_private_key: Option, ) -> io::Result<()> { let package_name = package_name.unwrap_or_default(); @@ -1115,6 +1116,60 @@ pub fn elf_to_tbf( } } + if ecdsa_nist_p256_private_key.is_some() { + let private_key_path_str = ecdsa_nist_p256_private_key.unwrap(); + let private_key_path = Path::new(&private_key_path_str); + let private_key_contents = read_rsa_file(private_key_path).unwrap_or_else(|e| { + panic!( + "Failed to read private key from {:?}: {:?}", + private_key_path, e + ); + }); + + let rng = rand::SystemRandom::new(); + + let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8( + &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, + &private_key_contents, + ) + .unwrap_or_else(|e| { + panic!("ECDSA NIST P256 could not be parsed: {:?}", e); + }); + + let signature = key_pair + .sign(&rng, &output[0..tbfheader.binary_end_offset() as usize]) + .map_err(|e| { + panic!("Could not generate ECDSA NIST P256 signature: {:?}", e); + }) + .unwrap(); + + let sig_len = signature.as_ref().len(); + let nist_p256_len = mem::size_of::() + + mem::size_of::() + + sig_len; // Signature + key is 32 bytes long + // Length in the TLV field + let nist_p256_tlv_len = nist_p256_len - mem::size_of::(); + + let mut credentials = vec![0; sig_len]; + + credentials[..sig_len].copy_from_slice(signature.as_ref()); + + let nist_p256_credentials = header::TbfFooterCredentials { + base: header::TbfHeaderTlv { + tipe: header::TbfHeaderTypes::Credentials, + length: nist_p256_len as u16, + }, + format: header::TbfFooterCredentialsType::EcdsaNistP256, + data: credentials, + }; + + output.write_all(nist_p256_credentials.generate().unwrap().get_ref())?; + footer_space_remaining -= nist_p256_tlv_len; + if verbose { + println!("Added PKCS#1v1.5 ECDSA NIST P256 signature credential."); + } + } + let padding_len = footer_space_remaining; // Need at least space for the base Credentials TLV. diff --git a/src/header.rs b/src/header.rs index 7f3b735..cbadb65 100644 --- a/src/header.rs +++ b/src/header.rs @@ -34,6 +34,7 @@ pub enum TbfFooterCredentialsType { SHA256 = 3, SHA384 = 4, SHA512 = 5, + EcdsaNistP256 = 6, } #[repr(C)] diff --git a/src/main.rs b/src/main.rs index 944da39..166e28a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -145,6 +145,7 @@ fn main() { opt.sha384_enable, opt.sha512_enable, opt.rsa4096_private_key.clone(), + opt.ecdsa_nist_p256_private_key.clone(), ) .unwrap(); if opt.verbose {