Skip to content

Commit

Permalink
ecdsa: provide der-encoded signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo committed Nov 28, 2023
1 parent 06e816a commit 77016e1
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 3 deletions.
48 changes: 46 additions & 2 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ hmac = { version = "0.12", optional = true }
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 }
spki = { version = "0.7.2", optional = true, default-features = false }
rusb = { version = "0.9", optional = true }
sha2 = { version = "0.10", optional = true }
tiny_http = { version = "0.12", optional = true }
Expand All @@ -54,9 +55,11 @@ tiny_http = { version = "0.12", optional = true }
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"]
der-signer = ["spki", "sha2/oid"]
http-server = ["tiny_http"]
http = []
mockhsm = ["digest", "ecdsa/arithmetic", "ed25519-dalek", "p256/ecdsa", "secp256k1"]
Expand All @@ -73,3 +76,6 @@ rustdoc-args = ["--cfg", "docsrs"]
[[example]]
name = "connector_http_server"
required-features = ["http-server", "usb"]

[patch.crates-io]
spki = { git = "https://github.com/baloo/formats.git", branch = "baloo/spki/from_key" }
38 changes: 38 additions & 0 deletions src/ecdsa/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ use std::ops::Add;
#[cfg(feature = "secp256k1")]
use super::{secp256k1::RecoveryId, Secp256k1};

#[cfg(feature = "der-signer")]
use {
ecdsa::{der, hazmat::DigestPrimitive},
spki::{
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
SignatureAlgorithmIdentifier,
},
};

/// ECDSA signature provider for yubihsm-client
#[derive(signature::Signer)]
pub struct Signer<C>
Expand Down Expand Up @@ -195,3 +204,32 @@ where
self.sign_prehash(&digest.finalize())
}
}

#[cfg(feature = "der-signer")]
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)
}
}

#[cfg(feature = "der-signer")]
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 = AnyRef<'static>;

const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
Signature::<C>::ALGORITHM_IDENTIFIER;
}
34 changes: 33 additions & 1 deletion tests/ecdsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ use yubihsm::{
object, Client,
};

#[cfg(feature = "der-signer")]
use {
::ecdsa::{der, signature::Keypair},
spki::SubjectPublicKeyInfoOwned,
std::{str::FromStr, time::Duration},
x509_cert::{
builder::{Builder, CertificateBuilder, Profile},
name::Name,
serial_number::SerialNumber,
time::Validity,
},
};

#[cfg(feature = "secp256k1")]
use {
::ecdsa::signature::{digest::Digest, DigestSigner, DigestVerifier},
Expand Down Expand Up @@ -69,7 +82,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 +118,22 @@ fn ecdsa_secp256k1_sign_recover_test() {
let signer_pk = PublicKey::from_encoded_point(signer.public_key()).unwrap();
assert_eq!(&recovered_pk, &signer_pk);
}

#[cfg(feature = "der-signer")]
#[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 77016e1

Please sign in to comment.