Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ECDSA NIST P256 signature credentials #87

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
58 changes: 58 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,63 @@ 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();

// Signature in R, S format is 64 bytes long
assert_eq!(sig_len, 64);

let nist_p256_len = mem::size_of::<header::TbfHeaderTlv>()
+ mem::size_of::<header::TbfFooterCredentialsType>()
+ sig_len;
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_tlv_len as u16,
},
format: header::TbfFooterCredentialsType::EcdsaNistP256,
data: credentials,
};

output.write_all(nist_p256_credentials.generate().unwrap().get_ref())?;
footer_space_remaining -= nist_p256_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
Loading