Skip to content

Commit

Permalink
Allow loading ECDSA private key from PKCS8 file missing public key
Browse files Browse the repository at this point in the history
PKCS8 encoded pem files have an option to have the public key in the
same file as the private key.

Not all pem files will have it, and the public key can be derived from
the private key anyway.

Fixes briansmith#2133

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
  • Loading branch information
aj-bagwell committed Aug 12, 2024
1 parent 7c0024a commit a6d4f74
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 8 deletions.
15 changes: 8 additions & 7 deletions src/ec/suite_b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ pub(crate) fn key_pair_from_pkcs8(
fn key_pair_from_pkcs8_<'a>(
template: &pkcs8::Template,
input: &mut untrusted::Reader<'a>,
) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::KeyRejected> {
) -> Result<(untrusted::Input<'a>, Option<untrusted::Input<'a>>), error::KeyRejected> {
let version = der::small_nonnegative_integer(input)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if version != 1 {
Expand All @@ -196,32 +196,33 @@ fn key_pair_from_pkcs8_<'a>(
}
}

// [1] publicKey. The RFC says it is optional, but we require it
// to be present.
// [1] publicKey. The RFC says it is optional.
let public_key = der::nested(
input,
der::Tag::ContextSpecificConstructed1,
error::Unspecified,
der::bit_string_with_no_unused_bits,
)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
.ok();

Ok((private_key, public_key))
}

pub(crate) fn key_pair_from_bytes(
curve: &'static ec::Curve,
private_key_bytes: untrusted::Input,
public_key_bytes: untrusted::Input,
public_key_bytes: Option<untrusted::Input>,
cpu_features: cpu::Features,
) -> Result<ec::KeyPair, error::KeyRejected> {
let seed = ec::Seed::from_bytes(curve, private_key_bytes, cpu_features)
.map_err(|error::Unspecified| error::KeyRejected::invalid_component())?;

let r = ec::KeyPair::derive(seed, cpu_features)
.map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?;
if public_key_bytes.as_slice_less_safe() != r.public_key().as_ref() {
return Err(error::KeyRejected::inconsistent_components());
if let Some(public_key_bytes) = public_key_bytes {
if public_key_bytes.as_slice_less_safe() != r.public_key().as_ref() {
return Err(error::KeyRejected::inconsistent_components());
}
}

Ok(r)
Expand Down
2 changes: 1 addition & 1 deletion src/ec/suite_b/ecdsa/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl EcdsaKeyPair {
let key_pair = ec::suite_b::key_pair_from_bytes(
alg.curve,
untrusted::Input::from(private_key),
untrusted::Input::from(public_key),
Some(untrusted::Input::from(public_key)),
cpu::features(),
)?;
Self::new(alg, key_pair, rng)
Expand Down

0 comments on commit a6d4f74

Please sign in to comment.