Skip to content

Commit

Permalink
Add support for ECDSA NIST P256 signature credentials
Browse files Browse the repository at this point in the history
Signed-off-by: Alistair Francis <[email protected]>
  • Loading branch information
alistair23 committed Sep 6, 2024
1 parent 4e9a056 commit 2537990
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
---------------

Expand Down
7 changes: 7 additions & 0 deletions src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ pub struct Opt {
help = "Add an 4096-bit RSA signature credential using this private key"
)]
pub rsa4096_private_key: Option<PathBuf>,

#[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<PathBuf>,
}

mod test {
Expand Down
55 changes: 55 additions & 0 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub fn elf_to_tbf(
sha384: bool,
sha512: bool,
rsa4096_private_key: Option<PathBuf>,
ecdsa_nist_p256_private_key: Option<PathBuf>,
) -> io::Result<()> {
let package_name = package_name.unwrap_or_default();

Expand Down Expand Up @@ -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::<header::TbfHeaderTlv>()
+ mem::size_of::<header::TbfFooterCredentialsType>()
+ sig_len; // Signature + key is 32 bytes long
// Length in the TLV field
let nist_p256_tlv_len = nist_p256_len - mem::size_of::<header::TbfHeaderTlv>();

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.
Expand Down
1 change: 1 addition & 0 deletions src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub enum TbfFooterCredentialsType {
SHA256 = 3,
SHA384 = 4,
SHA512 = 5,
EcdsaNistP256 = 6,
}

#[repr(C)]
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 2537990

Please sign in to comment.