diff --git a/Cargo.lock b/Cargo.lock index a292d84b..22b7f025 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,16 +483,16 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.104.0-alpha.2" +version = "0.104.0-alpha.3" dependencies = [ "aws-lc-rs", "base64", diff --git a/Cargo.toml b/Cargo.toml index b1eb6ee5..70f68d7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ license = "ISC" name = "rustls-webpki" readme = "README.md" repository = "https://github.com/rustls/webpki" -version = "0.104.0-alpha.2" +version = "0.104.0-alpha.3" include = [ "Cargo.toml", @@ -80,7 +80,7 @@ std = ["alloc", "pki-types/std"] [dependencies] aws-lc-rs = { version = "1.14", optional = true, default-features = false } -pki-types = { package = "rustls-pki-types", version = "1.13", default-features = false } +pki-types = { package = "rustls-pki-types", version = "1.13.2", default-features = false } ring = { version = "0.17", default-features = false, optional = true } untrusted = "0.9" diff --git a/src/aws_lc_rs_algs.rs b/src/aws_lc_rs_algs.rs index 4c4d1623..891df0b4 100644 --- a/src/aws_lc_rs_algs.rs +++ b/src/aws_lc_rs_algs.rs @@ -32,7 +32,7 @@ impl SignatureVerificationAlgorithm for AwsLcRsAlgorithm { ) -> Result<(), InvalidSignature> { if matches!( self.public_key_alg_id, - alg_id::ECDSA_P256 | alg_id::ECDSA_P384 | alg_id::ECDSA_P521 + alg_id::ECDSA_P256 | alg_id::ECDSA_P256K1 | alg_id::ECDSA_P384 | alg_id::ECDSA_P521 ) { // Restrict the allowed encodings of EC public keys. // @@ -87,6 +87,14 @@ pub static ML_DSA_87: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm { in_fips_submission: false, }; +/// ECDSA signatures using the K-256 curve and SHA-256. +pub static ECDSA_P256K1_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm { + public_key_alg_id: alg_id::ECDSA_P256K1, + signature_alg_id: alg_id::ECDSA_SHA256, + verification_alg: &signature::ECDSA_P256K1_SHA256_ASN1, + in_fips_submission: false, +}; + /// ECDSA signatures using the P-256 curve and SHA-256. pub static ECDSA_P256_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm { public_key_alg_id: alg_id::ECDSA_P256, @@ -308,6 +316,7 @@ mod tests { static SUPPORTED_ALGORITHMS_IN_TESTS: &[&dyn super::SignatureVerificationAlgorithm] = &[ // Reasonable algorithms. + super::ECDSA_P256K1_SHA256, super::ECDSA_P256_SHA256, super::ECDSA_P384_SHA384, super::ECDSA_P521_SHA256, diff --git a/src/lib.rs b/src/lib.rs index 4caf4282..9eabf49e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,9 +111,9 @@ pub mod ring { /// Signature verification algorithm implementations using the aws-lc-rs crypto library. pub mod aws_lc_rs { pub use super::aws_lc_rs_algs::{ - ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P256_SHA512, ECDSA_P384_SHA256, - ECDSA_P384_SHA384, ECDSA_P384_SHA512, ECDSA_P521_SHA256, ECDSA_P521_SHA384, - ECDSA_P521_SHA512, ED25519, RSA_PKCS1_2048_8192_SHA256, + ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P256_SHA512, ECDSA_P256K1_SHA256, + ECDSA_P384_SHA256, ECDSA_P384_SHA384, ECDSA_P384_SHA512, ECDSA_P521_SHA256, + ECDSA_P521_SHA384, ECDSA_P521_SHA512, ED25519, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA384, RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS, RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS, RSA_PKCS1_3072_8192_SHA384, @@ -159,6 +159,8 @@ pub static ALL_VERIFICATION_ALGS: &[&dyn pki_types::SignatureVerificationAlgorit #[cfg(all(feature = "ring", feature = "alloc"))] ring::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, #[cfg(feature = "aws-lc-rs")] + aws_lc_rs::ECDSA_P256K1_SHA256, + #[cfg(feature = "aws-lc-rs")] aws_lc_rs::ECDSA_P256_SHA256, #[cfg(feature = "aws-lc-rs")] aws_lc_rs::ECDSA_P256_SHA384, diff --git a/tests/client_auth_revocation.rs b/tests/client_auth_revocation.rs index 42ff8767..8caefbac 100644 --- a/tests/client_auth_revocation.rs +++ b/tests/client_auth_revocation.rs @@ -26,6 +26,8 @@ static ALGS: &[&dyn SignatureVerificationAlgorithm] = &[ #[cfg(feature = "ring")] webpki::ring::ECDSA_P256_SHA256, #[cfg(feature = "aws-lc-rs")] + webpki::aws_lc_rs::ECDSA_P256K1_SHA256, + #[cfg(feature = "aws-lc-rs")] webpki::aws_lc_rs::ECDSA_P256_SHA256, ]; diff --git a/tests/generate.py b/tests/generate.py index 15eac3c1..e1f78847 100755 --- a/tests/generate.py +++ b/tests/generate.py @@ -560,6 +560,7 @@ def signatures(force: bool) -> None: all_key_types: dict[str, ANY_PRIV_KEY] = { "ed25519": ed25519.Ed25519PrivateKey.generate(), "ecdsa_p256": ec.generate_private_key(ec.SECP256R1(), backend), + "ecdsa_p256k1": ec.generate_private_key(ec.SECP256K1(), backend), "ecdsa_p384": ec.generate_private_key(ec.SECP384R1(), backend), "ecdsa_p521": ec.generate_private_key(ec.SECP521R1(), backend), "rsa_1024_not_supported": rsa.generate_private_key( @@ -588,6 +589,7 @@ def signatures(force: bool) -> None: webpki_algs: dict[str, Iterable[str]] = { "ed25519": ["ED25519"], "ecdsa_p256": ["ECDSA_P256_SHA384", "ECDSA_P256_SHA256"], + "ecdsa_p256k1": ["ECDSA_P256K1_SHA256"], "ecdsa_p384": ["ECDSA_P384_SHA384", "ECDSA_P384_SHA256"], "ecdsa_p521": ["ECDSA_P521_SHA512", "ECDSA_P521_SHA256", "ECDSA_P521_SHA384"], "rsa_2048": rsa_types, @@ -607,6 +609,9 @@ def signatures(force: bool) -> None: how_to_sign: dict[str, SIGNER] = { "ED25519": lambda key, message: key.sign(message), + "ECDSA_P256K1_SHA256": lambda key, message: key.sign( + message, ec.ECDSA(hashes.SHA256()) + ), "ECDSA_P256_SHA256": lambda key, message: key.sign( message, ec.ECDSA(hashes.SHA256()) ), diff --git a/tests/signatures.rs b/tests/signatures.rs index 0b71e8b1..7a3924b6 100644 --- a/tests/signatures.rs +++ b/tests/signatures.rs @@ -28,11 +28,11 @@ use webpki::ring::{ #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] use webpki::aws_lc_rs::{ - ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384, ECDSA_P521_SHA256, - ECDSA_P521_SHA384, ECDSA_P521_SHA512, ED25519, RSA_PKCS1_2048_8192_SHA256, - RSA_PKCS1_2048_8192_SHA384, RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_3072_8192_SHA384, - RSA_PSS_2048_8192_SHA256_LEGACY_KEY, RSA_PSS_2048_8192_SHA384_LEGACY_KEY, - RSA_PSS_2048_8192_SHA512_LEGACY_KEY, + ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P256K1_SHA256, ECDSA_P384_SHA256, + ECDSA_P384_SHA384, ECDSA_P521_SHA256, ECDSA_P521_SHA384, ECDSA_P521_SHA512, ED25519, + RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_2048_8192_SHA384, RSA_PKCS1_2048_8192_SHA512, + RSA_PKCS1_3072_8192_SHA384, RSA_PSS_2048_8192_SHA256_LEGACY_KEY, + RSA_PSS_2048_8192_SHA384_LEGACY_KEY, RSA_PSS_2048_8192_SHA512_LEGACY_KEY, }; fn check_sig( @@ -111,6 +111,8 @@ fn ed25519_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, @@ -234,6 +236,94 @@ fn ecdsa_p256_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, + ECDSA_P384_SHA256, + ECDSA_P384_SHA384, + ED25519, + RSA_PKCS1_2048_8192_SHA256, + RSA_PKCS1_2048_8192_SHA384, + RSA_PKCS1_2048_8192_SHA512, + RSA_PKCS1_3072_8192_SHA384, + RSA_PSS_2048_8192_SHA256_LEGACY_KEY, + RSA_PSS_2048_8192_SHA384_LEGACY_KEY, + RSA_PSS_2048_8192_SHA512_LEGACY_KEY, + ] { + assert!(matches!( + check_sig(ee, *algorithm, b"", b""), + Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) + )); + } +} + +#[test] +#[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] +fn ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature() { + let ee = include_bytes!("signatures/ecdsa_p256k1.ee.der"); + let message = include_bytes!("signatures/message.bin"); + let signature = include_bytes!( + "signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature.sig.bin" + ); + assert_eq!( + check_sig(ee, ECDSA_P256K1_SHA256, message, signature), + Ok(()) + ); +} + +#[test] +#[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] +fn ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature_rpk() { + let rpk = include_bytes!("signatures/ecdsa_p256k1.spki.der"); + let message = include_bytes!("signatures/message.bin"); + let signature = include_bytes!( + "signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature.sig.bin" + ); + assert_eq!( + check_sig_rpk(rpk, ECDSA_P256K1_SHA256, message, signature), + Ok(()) + ); +} + +#[test] +#[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] +fn ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature() { + let ee = include_bytes!("signatures/ecdsa_p256k1.ee.der"); + let message = include_bytes!("signatures/message.bin"); + let signature = include_bytes!( + "signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature.sig.bin" + ); + assert_eq!( + check_sig(ee, ECDSA_P256K1_SHA256, message, signature), + Err(webpki::Error::InvalidSignatureForPublicKey) + ); +} + +#[test] +#[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] +fn ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature_rpk() { + let rpk = include_bytes!("signatures/ecdsa_p256k1.spki.der"); + let message = include_bytes!("signatures/message.bin"); + let signature = include_bytes!( + "signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature.sig.bin" + ); + assert_eq!( + check_sig_rpk(rpk, ECDSA_P256K1_SHA256, message, signature), + Err(webpki::Error::InvalidSignatureForPublicKey) + ); +} + +#[test] +fn ecdsa_p256k1_key_rejected_by_other_algorithms() { + let ee = include_bytes!("signatures/ecdsa_p256k1.ee.der"); + for algorithm in &[ + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P521_SHA256, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P521_SHA384, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P521_SHA512, + ECDSA_P256_SHA256, + ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384, ED25519, @@ -356,6 +446,8 @@ fn ecdsa_p384_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ED25519, @@ -531,6 +623,8 @@ fn ecdsa_p521_key_and_ecdsa_p521_sha384_detects_bad_signature_rpk() { fn ecdsa_p521_key_rejected_by_other_algorithms() { let ee = include_bytes!("signatures/ecdsa_p521.ee.der"); for algorithm in &[ + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, @@ -873,6 +967,8 @@ fn rsa_2048_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, @@ -1260,6 +1356,8 @@ fn rsa_3072_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, @@ -1647,6 +1745,8 @@ fn rsa_4096_key_rejected_by_other_algorithms() { ECDSA_P521_SHA384, #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] ECDSA_P521_SHA512, + #[cfg(all(not(feature = "ring"), feature = "aws-lc-rs"))] + ECDSA_P256K1_SHA256, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, diff --git a/tests/signatures/ecdsa_p256k1.ee.der b/tests/signatures/ecdsa_p256k1.ee.der new file mode 100644 index 00000000..3162d001 Binary files /dev/null and b/tests/signatures/ecdsa_p256k1.ee.der differ diff --git a/tests/signatures/ecdsa_p256k1.spki.der b/tests/signatures/ecdsa_p256k1.spki.der new file mode 100644 index 00000000..9acbf995 Binary files /dev/null and b/tests/signatures/ecdsa_p256k1.spki.der differ diff --git a/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature.sig.bin b/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature.sig.bin new file mode 100644 index 00000000..4302da2f Binary files /dev/null and b/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_detects_bad_signature.sig.bin differ diff --git a/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature.sig.bin b/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature.sig.bin new file mode 100644 index 00000000..bcb1658d Binary files /dev/null and b/tests/signatures/ecdsa_p256k1_key_and_ecdsa_p256k1_sha256_good_signature.sig.bin differ