Skip to content

Commit

Permalink
ecdsa: provide der-encoded signatures (#506)
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo authored Dec 9, 2023
1 parent 2a0be95 commit fca6e17
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 7 deletions.
45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bitflags = "2"
cmac = "0.7"
cbc = "0.1"
ccm = { version = "0.5", features = ["std"] }
ecdsa = { version = "0.16", default-features = false }
ecdsa = { version = "0.16", default-features = false, features = ["pkcs8"] }
ed25519 = "2"
log = "0.4"
num-traits = "0.2"
Expand All @@ -32,6 +32,8 @@ serde = { version = "1", features = ["serde_derive"] }
rand_core = { version = "0.6", features = ["std"] }
rsa = "0.9.6"
signature = { version = "2", features = ["derive"] }
sha2 = { version = "0.10", features = ["oid"] }
spki = { version = "0.7.3", default-features = false }
subtle = "2"
thiserror = "1"
time = { version = "0.3", features = ["serde"] }
Expand All @@ -46,23 +48,23 @@ k256 = { version = "0.13", optional = true, features = ["ecdsa", "sha256"] }
pbkdf2 = { version = "0.12", optional = true, default-features = false, features = ["hmac"] }
serde_json = { version = "1", optional = true }
rusb = { version = "0.9", optional = true }
sha2 = { version = "0.10", optional = true }
tiny_http = { version = "0.12", optional = true }

[dev-dependencies]
ed25519-dalek = "2"
once_cell = "1"
p256 = { version = "0.13", features = ["ecdsa"] }
x509-cert = { version = "0.2.4", features = ["builder"] }

[features]
default = ["http", "passwords", "setup"]
http-server = ["tiny_http"]
http = []
mockhsm = ["digest", "ecdsa/arithmetic", "ed25519-dalek", "p256/ecdsa", "secp256k1"]
passwords = ["hmac", "pbkdf2", "sha2"]
passwords = ["hmac", "pbkdf2"]
secp256k1 = ["k256"]
setup = ["passwords", "serde_json", "uuid/serde"]
untested = ["sha2"]
untested = []
usb = ["rusb"]

[package.metadata.docs.rs]
Expand Down
2 changes: 1 addition & 1 deletion src/authentication/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use zeroize::Zeroize;
#[cfg(feature = "pbkdf2")]
use pbkdf2::pbkdf2_hmac;

#[cfg(feature = "sha2")]
#[cfg(feature = "passwords")]
use sha2::Sha256;

/// Auth keys are 2 * AES-128 keys
Expand Down
32 changes: 32 additions & 0 deletions src/ecdsa/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@
use super::{algorithm::CurveAlgorithm, NistP256, NistP384};
use crate::{object, Client};
use ecdsa::{
der,
elliptic_curve::{
consts::U32,
generic_array::ArrayLength,
point::PointCompression,
sec1::{self, FromEncodedPoint, ToEncodedPoint},
AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve,
},
hazmat::DigestPrimitive,
Signature, SignatureSize, VerifyingKey,
};
use signature::{digest::Digest, hazmat::PrehashSigner, DigestSigner, Error, KeypairRef};
use spki::{
der::AnyRef, AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier,
};
use std::ops::Add;

#[cfg(feature = "secp256k1")]
Expand Down Expand Up @@ -195,3 +200,30 @@ where
self.sign_prehash(&digest.finalize())
}
}

impl<C> DigestSigner<C::Digest, der::Signature<C>> for Signer<C>
where
C: CurveAlgorithm + CurveArithmetic + PointCompression + PrimeCurve + DigestPrimitive,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: sec1::ModulusSize,
ecdsa::der::MaxSize<C>: ArrayLength<u8>,
<FieldBytesSize<C> as Add>::Output: Add<ecdsa::der::MaxOverhead> + ArrayLength<u8>,
Self: DigestSigner<C::Digest, Signature<C>>,
{
fn try_sign_digest(&self, digest: C::Digest) -> Result<der::Signature<C>, Error> {
DigestSigner::<C::Digest, Signature<C>>::try_sign_digest(self, digest).map(Into::into)
}
}

impl<C> SignatureAlgorithmIdentifier for Signer<C>
where
C: CurveAlgorithm + CurveArithmetic + PointCompression + PrimeCurve,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
FieldBytesSize<C>: sec1::ModulusSize,
Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
{
type Params = <VerifyingKey<C> as SignatureAlgorithmIdentifier>::Params;

const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
<VerifyingKey<C> as SignatureAlgorithmIdentifier>::SIGNATURE_ALGORITHM_IDENTIFIER;
}
31 changes: 29 additions & 2 deletions tests/ecdsa/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
//! Elliptic Curve Digital Signature Algorithm (ECDSA) tests
use ::ecdsa::{
der,
elliptic_curve::{
point::PointCompression,
sec1::{self, FromEncodedPoint, ToEncodedPoint},
AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve,
},
signature::Verifier,
signature::{Keypair, Verifier},
};
use spki::SubjectPublicKeyInfoOwned;
use std::{str::FromStr, time::Duration};
use x509_cert::{
builder::{Builder, CertificateBuilder, Profile},
name::Name,
serial_number::SerialNumber,
time::Validity,
};
use yubihsm::{
asymmetric::signature::Signer as _,
Expand Down Expand Up @@ -69,7 +78,7 @@ fn ecdsa_nistp256_sign_test() {
let signer = create_signer::<NistP256>(201);
let verify_key = p256::ecdsa::VerifyingKey::from_encoded_point(signer.public_key()).unwrap();

let signature = signer.sign(TEST_MESSAGE);
let signature: ecdsa::Signature<NistP256> = signer.sign(TEST_MESSAGE);
assert!(verify_key.verify(TEST_MESSAGE, &signature).is_ok());
}

Expand Down Expand Up @@ -105,3 +114,21 @@ fn ecdsa_secp256k1_sign_recover_test() {
let signer_pk = PublicKey::from_encoded_point(signer.public_key()).unwrap();
assert_eq!(&recovered_pk, &signer_pk);
}

#[test]
fn ecdsa_nistp256_ca() {
let signer = create_signer::<NistP256>(204);

let serial_number = SerialNumber::from(42u32);
let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
let profile = Profile::Root;
let subject =
Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
let pub_key = SubjectPublicKeyInfoOwned::from_key(signer.verifying_key()).unwrap();

let builder =
CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
.expect("Create certificate");

builder.build::<der::Signature<NistP256>>().unwrap();
}

0 comments on commit fca6e17

Please sign in to comment.