diff --git a/Cargo.lock b/Cargo.lock index d10e9e9..4f4f754 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ dependencies = [ [[package]] name = "card-cli" -version = "1.12.4" +version = "1.12.5" dependencies = [ "aes-gcm-stream", "authenticator 0.3.1", @@ -528,6 +528,7 @@ dependencies = [ "openssl", "p256 0.13.2", "p384 0.13.1", + "p521", "pem", "pinentry", "rand 0.8.5", @@ -2482,6 +2483,20 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct 0.2.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "rand_core 0.6.4", + "sha2 0.10.8", +] + [[package]] name = "papergrid" version = "0.10.0" diff --git a/Cargo.toml b/Cargo.toml index fd58452..cffdb6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "card-cli" -version = "1.12.4" +version = "1.12.5" authors = ["Hatter Jiang "] edition = "2018" @@ -40,6 +40,7 @@ x509-parser = { version = "0.15", features = ["verify"] } ssh-agent = { version = "0.2", features = ["agent"] } p256 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] } p384 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] } +p521 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] } spki = { version = "0.7", features = ["pem"] } tabled = "0.14" env_logger = "0.10" diff --git a/src/cmd_external_public_key.rs b/src/cmd_external_public_key.rs index 43453d3..8db06c4 100644 --- a/src/cmd_external_public_key.rs +++ b/src/cmd_external_public_key.rs @@ -71,6 +71,7 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult) -> XResult EcdsaAlgorithm::P256, "p384" => EcdsaAlgorithm::P384, + "p521" => EcdsaAlgorithm::P521, _ => { return simple_error!("Key type must be p256 or p384"); } diff --git a/src/cmd_sign_jwt_soft.rs b/src/cmd_sign_jwt_soft.rs index 1482435..6a50290 100644 --- a/src/cmd_sign_jwt_soft.rs +++ b/src/cmd_sign_jwt_soft.rs @@ -89,6 +89,7 @@ pub fn convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm: AlgorithmType) -> match jwt_algorithm { AlgorithmType::Es256 => Ok(EcdsaAlgorithm::P256), AlgorithmType::Es384 => Ok(EcdsaAlgorithm::P384), + AlgorithmType::Es512 => Ok(EcdsaAlgorithm::P521), _ => simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm), } } @@ -96,10 +97,12 @@ pub fn convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm: AlgorithmType) -> pub fn parse_ecdsa_private_key(private_key: &str) -> XResult<(AlgorithmType, Vec)> { let p256_private_key_d = ecdsautil::parse_p256_private_key(private_key).ok(); let p384_private_key_d = ecdsautil::parse_p384_private_key(private_key).ok(); + let p521_private_key_d = ecdsautil::parse_p521_private_key(private_key).ok(); - let (jwt_algorithm, private_key_d) = match (p256_private_key_d, p384_private_key_d) { - (Some(p256_private_key_d), None) => (AlgorithmType::Es256, p256_private_key_d), - (None, Some(p384_private_key_d)) => (AlgorithmType::Es384, p384_private_key_d), + let (jwt_algorithm, private_key_d) = match (p256_private_key_d, p384_private_key_d, p521_private_key_d) { + (Some(p256_private_key_d), None, None) => (AlgorithmType::Es256, p256_private_key_d), + (None, Some(p384_private_key_d), None) => (AlgorithmType::Es384, p384_private_key_d), + (None, None, Some(p521_private_key_d)) => (AlgorithmType::Es512, p521_private_key_d), _ => return simple_error!("Invalid private key: {}", private_key), }; Ok((jwt_algorithm, private_key_d)) diff --git a/src/ecdsautil.rs b/src/ecdsautil.rs index e512a84..a95ff30 100644 --- a/src/ecdsautil.rs +++ b/src/ecdsautil.rs @@ -6,6 +6,7 @@ use p256::ecdsa::signature::hazmat::PrehashVerifier; use p256::elliptic_curve::JwkEcKey; use p384::NistP384; use p256::pkcs8::EncodePrivateKey; +use p521::NistP521; use rust_util::XResult; use spki::EncodePublicKey; use crate::util::{base64_encode, try_decode}; @@ -14,6 +15,7 @@ use crate::util::{base64_encode, try_decode}; pub enum EcdsaAlgorithm { P256, P384, + P521, } #[derive(Copy, Clone, Eq, PartialEq)] @@ -83,19 +85,12 @@ macro_rules! generate_inner_ecdsa_keypair { pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec, JwkEcKey)> { match algo { - EcdsaAlgorithm::P256 => generate_p256_keypair(), - EcdsaAlgorithm::P384 => generate_p384_keypair(), + EcdsaAlgorithm::P256 => generate_inner_ecdsa_keypair!(p256), + EcdsaAlgorithm::P384 => generate_inner_ecdsa_keypair!(p384), + EcdsaAlgorithm::P521 => generate_inner_ecdsa_keypair!(p521), } } -pub fn generate_p256_keypair() -> XResult<(String, String, String, Vec, JwkEcKey)> { - generate_inner_ecdsa_keypair!(p256) -} - -pub fn generate_p384_keypair() -> XResult<(String, String, String, Vec, JwkEcKey)> { - generate_inner_ecdsa_keypair!(p384) -} - macro_rules! parse_ecdsa_private_key_to_public_key { ($algo: tt, $parse_ecdsa_private_key: tt) => ({ @@ -125,6 +120,10 @@ pub fn parse_p384_private_key_to_public_key(private_key_pkcs8: &str) -> XResult< parse_ecdsa_private_key_to_public_key!(p384, private_key_pkcs8) } +pub fn parse_p521_private_key_to_public_key(private_key_pkcs8: &str) -> XResult> { + parse_ecdsa_private_key_to_public_key!(p521, private_key_pkcs8) +} + macro_rules! parse_ecdsa_private_key { ($algo: tt, $parse_ecdsa_private_key: tt) => ({ @@ -153,6 +152,10 @@ pub fn parse_p384_private_key(private_key_pkcs8: &str) -> XResult> { parse_ecdsa_private_key!(p384, private_key_pkcs8) } +pub fn parse_p521_private_key(private_key_pkcs8: &str) -> XResult> { + parse_ecdsa_private_key!(p521, private_key_pkcs8) +} + macro_rules! sign_ecdsa_rs_or_der { ($algo: tt, $private_key_d: tt, $pre_hash: tt, $is_rs: tt) => ({ @@ -171,20 +174,14 @@ macro_rules! sign_ecdsa_rs_or_der { } pub fn ecdsa_sign(algo: EcdsaAlgorithm, private_key_d: &[u8], pre_hash: &[u8], sign_type: EcdsaSignType) -> XResult> { + let is_rs = sign_type == EcdsaSignType::Rs; match algo { - EcdsaAlgorithm::P256 => sign_p256_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs), - EcdsaAlgorithm::P384 => sign_p384_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs), + EcdsaAlgorithm::P256 => sign_ecdsa_rs_or_der!(p256, private_key_d, pre_hash, is_rs), + EcdsaAlgorithm::P384 => sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs), + EcdsaAlgorithm::P521 => sign_ecdsa_rs_or_der!(p521, private_key_d, pre_hash, is_rs), } } -pub fn sign_p256_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult> { - sign_ecdsa_rs_or_der!(p256, private_key_d, pre_hash, is_rs) -} - -pub fn sign_p384_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult> { - sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs) -} - macro_rules! ecdsa_verify_signature { ($algo: tt, $pk_point: tt, $prehash: tt, $signature: tt) => ({ @@ -205,6 +202,7 @@ pub fn ecdsa_verify(algo: EcdsaAlgorithm, pk_point: &[u8], prehash: &[u8], signa match algo { EcdsaAlgorithm::P256 => ecdsa_verify_signature!(NistP256, pk_point, prehash, signature), EcdsaAlgorithm::P384 => ecdsa_verify_signature!(NistP384, pk_point, prehash, signature), + EcdsaAlgorithm::P521 => ecdsa_verify_signature!(NistP521, pk_point, prehash, signature), } Ok(()) } \ No newline at end of file