From 6cc1a565614a24cb3c86f1f714d922315459b9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 22 Oct 2024 16:11:24 +0200 Subject: [PATCH] Add support for secp256k1 --- Cargo.toml | 2 +- src/card.rs | 4 +++ src/command/gen.rs | 22 +++++++++++++++- src/command/private_key_template.rs | 3 +++ src/command/pso.rs | 14 ++++++++++ src/types.rs | 31 +++++++++++++++++----- tests/brainpool-p512r1.rs | 2 +- tests/gpg/mod.rs | 41 +++++++++++++++++++++++++---- tests/secp256k1-import.rs | 12 +++++++++ tests/secp256k1.rs | 12 +++++++++ 10 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 tests/secp256k1-import.rs create mode 100644 tests/secp256k1.rs diff --git a/Cargo.toml b/Cargo.toml index c519e40..c6cbe3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,7 +96,7 @@ log-error = [] [patch.crates-io] p256-cortex-m4 = { git = "https://github.com/Nitrokey/p256-cortex-m4", tag = "v0.1.0-alpha.6-nitrokey-1" } -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "046478b7a4f6e2315acf9112d98308379c2e3eee" } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "316a96f66335eab8b4195e900cda1a768ed1b99e" } trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth.git", rev = "c030b82ad3441f337af09afe3a69e8a6da5785ea"} trussed-chunked = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "chunked-v0.1.0" } trussed-manage = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "manage-v0.1.0" } diff --git a/src/card.rs b/src/card.rs index 07e5b78..fa8051a 100644 --- a/src/card.rs +++ b/src/card.rs @@ -185,6 +185,8 @@ bitflags! { const BRAINPOOL_P384R1 = 1 << 9; /// BRAINPOOL_P521R1 Brainpool curve const BRAINPOOL_P512R1 = 1 << 10; + /// SECP256k1 (bitcoin curve) + const SECP256K1 = 1 << 11; } } @@ -202,6 +204,7 @@ impl AllowedAlgorithms { Self::RSA_4096, Self::X_25519, Self::ED_25519, + Self::SECP256K1, ] .into_iter() .fold(Self::empty(), |acc, value| acc | value) @@ -219,6 +222,7 @@ impl AllowedAlgorithms { Self::RSA_4096, Self::X_25519, Self::ED_25519, + Self::SECP256K1, ] .into_iter() .fold(Self::empty(), |acc, value| acc | value) diff --git a/src/command/gen.rs b/src/command/gen.rs index 0a01452..a7c02bb 100644 --- a/src/command/gen.rs +++ b/src/command/gen.rs @@ -32,7 +32,9 @@ fn serialize_pub( | CurveAlgo::EcDsaBrainpoolP384R1 | CurveAlgo::EcDhBrainpoolP384R1 | CurveAlgo::EcDsaBrainpoolP512R1 - | CurveAlgo::EcDhBrainpoolP512R1 => serialize_nist_curve(ctx, public_key), + | CurveAlgo::EcDhBrainpoolP512R1 + | CurveAlgo::EcDhSecp256k1 + | CurveAlgo::EcDsaSecp256k1 => serialize_nist_curve(ctx, public_key), CurveAlgo::X255 | CurveAlgo::Ed255 => serialize_25519(ctx, public_key), } } @@ -66,6 +68,9 @@ pub fn sign( SignatureAlgorithm::EcDsaBrainpoolP512R1 => { gen_ec_key(ctx.lend(), KeyType::Sign, CurveAlgo::EcDsaBrainpoolP512R1) } + SignatureAlgorithm::EcDsaSecp256k1 => { + gen_ec_key(ctx.lend(), KeyType::Sign, CurveAlgo::EcDsaSecp256k1) + } SignatureAlgorithm::Rsa2048 => { gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa2048Pkcs1v15) } @@ -101,6 +106,9 @@ pub fn dec( DecryptionAlgorithm::EcDhBrainpoolP512R1 => { gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::EcDhBrainpoolP512R1) } + DecryptionAlgorithm::EcDhSecp256k1 => { + gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::EcDhSecp256k1) + } DecryptionAlgorithm::Rsa2048 => { gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa2048Pkcs1v15) } @@ -142,6 +150,9 @@ pub fn aut( AuthenticationAlgorithm::EcDsaBrainpoolP512R1 => { gen_ec_key(ctx.lend(), KeyType::Aut, CurveAlgo::EcDsaBrainpoolP512R1) } + AuthenticationAlgorithm::EcDsaSecp256k1 => { + gen_ec_key(ctx.lend(), KeyType::Aut, CurveAlgo::EcDsaSecp256k1) + } AuthenticationAlgorithm::Rsa2048 => { gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa2048Pkcs1v15) } @@ -263,6 +274,9 @@ pub fn read_sign( SignatureAlgorithm::EcDsaBrainpoolP512R1 => { read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaBrainpoolP512R1) } + SignatureAlgorithm::EcDsaSecp256k1 => { + read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaSecp256k1) + } SignatureAlgorithm::Rsa2048 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs1v15), SignatureAlgorithm::Rsa3072 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa3072Pkcs1v15), SignatureAlgorithm::Rsa4096 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs1v15), @@ -293,6 +307,9 @@ pub fn read_dec( DecryptionAlgorithm::EcDhBrainpoolP512R1 => { read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDhBrainpoolP512R1) } + DecryptionAlgorithm::EcDhSecp256k1 => { + read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDhSecp256k1) + } DecryptionAlgorithm::Rsa2048 => { read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs1v15) } @@ -329,6 +346,9 @@ pub fn read_aut( AuthenticationAlgorithm::EcDsaBrainpoolP512R1 => { read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaBrainpoolP512R1) } + AuthenticationAlgorithm::EcDsaSecp256k1 => { + read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaSecp256k1) + } AuthenticationAlgorithm::Rsa2048 => { read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs1v15) } diff --git a/src/command/private_key_template.rs b/src/command/private_key_template.rs index aa56d66..92be931 100644 --- a/src/command/private_key_template.rs +++ b/src/command/private_key_template.rs @@ -58,6 +58,7 @@ pub fn put_sign( SignatureAlgorithm::EcDsaBrainpoolP512R1 => { put_ec(ctx.lend(), CurveAlgo::EcDsaBrainpoolP512R1)? } + SignatureAlgorithm::EcDsaSecp256k1 => put_ec(ctx.lend(), CurveAlgo::EcDsaSecp256k1)?, SignatureAlgorithm::Ed255 => put_ec(ctx.lend(), CurveAlgo::Ed255)?, SignatureAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, SignatureAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, @@ -99,6 +100,7 @@ pub fn put_dec( DecryptionAlgorithm::EcDhBrainpoolP512R1 => { put_ec(ctx.lend(), CurveAlgo::EcDhBrainpoolP512R1)? } + DecryptionAlgorithm::EcDhSecp256k1 => put_ec(ctx.lend(), CurveAlgo::EcDhSecp256k1)?, DecryptionAlgorithm::X255 => put_ec(ctx.lend(), CurveAlgo::X255)?, DecryptionAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, DecryptionAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, @@ -140,6 +142,7 @@ pub fn put_aut( AuthenticationAlgorithm::EcDsaBrainpoolP512R1 => { put_ec(ctx.lend(), CurveAlgo::EcDsaBrainpoolP512R1)? } + AuthenticationAlgorithm::EcDsaSecp256k1 => put_ec(ctx.lend(), CurveAlgo::EcDsaSecp256k1)?, AuthenticationAlgorithm::Ed255 => put_ec(ctx.lend(), CurveAlgo::Ed255)?, AuthenticationAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, AuthenticationAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, diff --git a/src/command/pso.rs b/src/command/pso.rs index f0ddd06..247d2c5 100644 --- a/src/command/pso.rs +++ b/src/command/pso.rs @@ -94,6 +94,12 @@ pub fn sign( } sign_ec(ctx.lend(), key_id, Mechanism::BrainpoolP512R1Prehashed) } + SignatureAlgorithm::EcDsaSecp256k1 => { + if ctx.data.len() != 32 { + return Err(Status::ConditionsOfUseNotSatisfied); + } + sign_ec(ctx.lend(), key_id, Mechanism::Secp256k1Prehashed) + } SignatureAlgorithm::Rsa2048 => sign_rsa(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs1v15), SignatureAlgorithm::Rsa3072 => sign_rsa(ctx.lend(), key_id, Mechanism::Rsa3072Pkcs1v15), SignatureAlgorithm::Rsa4096 => sign_rsa(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs1v15), @@ -172,6 +178,9 @@ fn int_aut_key_mecha_uif( AuthenticationAlgorithm::EcDsaBrainpoolP512R1 => { (Mechanism::BrainpoolP512R1Prehashed, RsaOrEcc::Ecc) } + AuthenticationAlgorithm::EcDsaSecp256k1 => { + (Mechanism::Secp256k1Prehashed, RsaOrEcc::Ecc) + } AuthenticationAlgorithm::Ed255 => (Mechanism::Ed255, RsaOrEcc::Ecc), AuthenticationAlgorithm::Rsa2048 => (Mechanism::Rsa2048Pkcs1v15, RsaOrEcc::Rsa), @@ -198,6 +207,9 @@ fn int_aut_key_mecha_uif( DecryptionAlgorithm::EcDhBrainpoolP512R1 => { (Mechanism::BrainpoolP512R1Prehashed, RsaOrEcc::Ecc) } + DecryptionAlgorithm::EcDhSecp256k1 => { + (Mechanism::Secp256k1Prehashed, RsaOrEcc::Ecc) + } DecryptionAlgorithm::Rsa2048 => (Mechanism::Rsa2048Pkcs1v15, RsaOrEcc::Rsa), DecryptionAlgorithm::Rsa3072 => (Mechanism::Rsa3072Pkcs1v15, RsaOrEcc::Rsa), DecryptionAlgorithm::Rsa4096 => (Mechanism::Rsa4096Pkcs1v15, RsaOrEcc::Rsa), @@ -271,6 +283,7 @@ fn decipher_key_mecha_uif( DecryptionAlgorithm::EcDhBrainpoolP512R1 => { (Mechanism::BrainpoolP512R1, RsaOrEcc::Ecc) } + DecryptionAlgorithm::EcDhSecp256k1 => (Mechanism::Secp256k1, RsaOrEcc::Ecc), DecryptionAlgorithm::Rsa2048 => (Mechanism::Rsa2048Pkcs1v15, RsaOrEcc::Rsa), DecryptionAlgorithm::Rsa3072 => (Mechanism::Rsa3072Pkcs1v15, RsaOrEcc::Rsa), DecryptionAlgorithm::Rsa4096 => (Mechanism::Rsa4096Pkcs1v15, RsaOrEcc::Rsa), @@ -291,6 +304,7 @@ fn decipher_key_mecha_uif( AuthenticationAlgorithm::EcDsaBrainpoolP512R1 => { (Mechanism::BrainpoolP512R1, RsaOrEcc::Ecc) } + AuthenticationAlgorithm::EcDsaSecp256k1 => (Mechanism::Secp256k1, RsaOrEcc::Ecc), AuthenticationAlgorithm::Ed255 => { warn!("Attempt to decipher with Ed255 key"); return Err(Status::ConditionsOfUseNotSatisfied); diff --git a/src/types.rs b/src/types.rs index 6cea6f6..6bcfafd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -90,26 +90,30 @@ macro_rules! iterable_sub_enum { } } -const ED255_ATTRIBUTES: &[u8] = hex!("16 2B 06 01 04 01 DA 47 0F 01").as_slice(); -const ED255_ATTRIBUTES_PK: &[u8] = hex!("16 2B 06 01 04 01 DA 47 0F 01 FF").as_slice(); -const ECDSA_P256_ATTRIBUTES: &[u8] = hex!("13 2A 86 48 CE 3D 03 01 07").as_slice(); +const ED255_ATTRIBUTES: &[u8] = hex!("162B06010401DA470F01").as_slice(); +const ED255_ATTRIBUTES_PK: &[u8] = hex!("162B06010401DA470F01 FF").as_slice(); +const ECDSA_P256_ATTRIBUTES: &[u8] = hex!("132A8648CE3D030107").as_slice(); const ECDSA_P384_ATTRIBUTES: &[u8] = hex!("132b81040022").as_slice(); const ECDSA_P521_ATTRIBUTES: &[u8] = hex!("132b81040023").as_slice(); -const ECDSA_P256_ATTRIBUTES_PK: &[u8] = hex!("13 2A 86 48 CE 3D 03 01 07 FF").as_slice(); +const ECDSA_P256_ATTRIBUTES_PK: &[u8] = hex!("132A8648CE3D030107 FF").as_slice(); const ECDSA_P384_ATTRIBUTES_PK: &[u8] = hex!("132b81040022 FF").as_slice(); const ECDSA_P521_ATTRIBUTES_PK: &[u8] = hex!("132b81040023 FF").as_slice(); +const ECDSA_SECP256K1_ATTRIBUTES: &[u8] = hex!("132B8104000A").as_slice(); +const ECDSA_SECP256K1_ATTRIBUTES_PK: &[u8] = hex!("132B8104000A FF").as_slice(); const ECDSA_BRAINPOOL_P256R1_ATTRIBUTES: &[u8] = hex!("132b2403030208010107").as_slice(); const ECDSA_BRAINPOOL_P384R1_ATTRIBUTES: &[u8] = hex!("132b240303020801010b").as_slice(); const ECDSA_BRAINPOOL_P512R1_ATTRIBUTES: &[u8] = hex!("132b240303020801010d").as_slice(); const ECDSA_BRAINPOOL_P256R1_ATTRIBUTES_PK: &[u8] = hex!("132b2403030208010107 FF").as_slice(); const ECDSA_BRAINPOOL_P384R1_ATTRIBUTES_PK: &[u8] = hex!("132b240303020801010b FF").as_slice(); const ECDSA_BRAINPOOL_P512R1_ATTRIBUTES_PK: &[u8] = hex!("132b240303020801010d FF").as_slice(); -const ECDH_P256_ATTRIBUTES: &[u8] = hex!("12 2A 86 48 CE 3D 03 01 07").as_slice(); +const ECDH_P256_ATTRIBUTES: &[u8] = hex!("122A8648CE3D030107").as_slice(); const ECDH_P384_ATTRIBUTES: &[u8] = hex!("122b81040022").as_slice(); const ECDH_P521_ATTRIBUTES: &[u8] = hex!("122b81040023").as_slice(); -const ECDH_P256_ATTRIBUTES_PK: &[u8] = hex!("12 2A 86 48 CE 3D 03 01 07 FF").as_slice(); +const ECDH_P256_ATTRIBUTES_PK: &[u8] = hex!("122A8648CE3D030107 FF").as_slice(); const ECDH_P384_ATTRIBUTES_PK: &[u8] = hex!("122b81040022 FF").as_slice(); const ECDH_P521_ATTRIBUTES_PK: &[u8] = hex!("122b81040023 FF").as_slice(); +const ECDH_SECP256K1_ATTRIBUTES: &[u8] = hex!("122B8104000A").as_slice(); +const ECDH_SECP256K1_ATTRIBUTES_PK: &[u8] = hex!("122B8104000A FF").as_slice(); const ECDH_BRAINPOOL_P256R1_ATTRIBUTES: &[u8] = hex!("122b2403030208010107").as_slice(); const ECDH_BRAINPOOL_P384R1_ATTRIBUTES: &[u8] = hex!("122b240303020801010b").as_slice(); const ECDH_BRAINPOOL_P512R1_ATTRIBUTES: &[u8] = hex!("122b240303020801010d").as_slice(); @@ -180,6 +184,8 @@ iterable_enum! { EcDsaP384, EcDhP521, EcDsaP521, + EcDhSecp256k1, + EcDsaSecp256k1, EcDhBrainpoolP256R1, EcDsaBrainpoolP256R1, EcDhBrainpoolP384R1, @@ -202,6 +208,8 @@ impl TryFrom<&[u8]> for Algorithm { ECDSA_P384_ATTRIBUTES | ECDSA_P384_ATTRIBUTES_PK => Ok(Self::EcDsaP384), ECDH_P521_ATTRIBUTES | ECDH_P521_ATTRIBUTES_PK => Ok(Self::EcDhP521), ECDSA_P521_ATTRIBUTES | ECDSA_P521_ATTRIBUTES_PK => Ok(Self::EcDsaP521), + ECDSA_SECP256K1_ATTRIBUTES | ECDSA_SECP256K1_ATTRIBUTES_PK => Ok(Self::EcDsaSecp256k1), + ECDH_SECP256K1_ATTRIBUTES | ECDH_SECP256K1_ATTRIBUTES_PK => Ok(Self::EcDhSecp256k1), ECDH_BRAINPOOL_P256R1_ATTRIBUTES | ECDH_BRAINPOOL_P256R1_ATTRIBUTES_PK => { Ok(Self::EcDhBrainpoolP256R1) } @@ -247,6 +255,8 @@ impl Algorithm { Self::EcDsaP384 => ECDSA_P384_ATTRIBUTES_PK, Self::EcDhP521 => ECDH_P521_ATTRIBUTES_PK, Self::EcDsaP521 => ECDSA_P521_ATTRIBUTES_PK, + Self::EcDhSecp256k1 => ECDH_SECP256K1_ATTRIBUTES_PK, + Self::EcDsaSecp256k1 => ECDSA_SECP256K1_ATTRIBUTES_PK, Self::EcDhBrainpoolP256R1 => ECDH_BRAINPOOL_P256R1_ATTRIBUTES_PK, Self::EcDsaBrainpoolP256R1 => ECDSA_BRAINPOOL_P256R1_ATTRIBUTES_PK, Self::EcDhBrainpoolP384R1 => ECDH_BRAINPOOL_P384R1_ATTRIBUTES_PK, @@ -273,6 +283,8 @@ impl Algorithm { Self::EcDsaP384 => allowed.contains(AllowedAlgorithms::P_384), Self::EcDhP521 => allowed.contains(AllowedAlgorithms::P_521), Self::EcDsaP521 => allowed.contains(AllowedAlgorithms::P_521), + Self::EcDsaSecp256k1 => allowed.contains(AllowedAlgorithms::SECP256K1), + Self::EcDhSecp256k1 => allowed.contains(AllowedAlgorithms::SECP256K1), Self::EcDhBrainpoolP256R1 => allowed.contains(AllowedAlgorithms::BRAINPOOL_P256R1), Self::EcDsaBrainpoolP256R1 => allowed.contains(AllowedAlgorithms::BRAINPOOL_P256R1), Self::EcDhBrainpoolP384R1 => allowed.contains(AllowedAlgorithms::BRAINPOOL_P384R1), @@ -301,6 +313,7 @@ iterable_sub_enum! { EcDsaBrainpoolP256R1, EcDsaBrainpoolP384R1, EcDsaBrainpoolP512R1, + EcDsaSecp256k1, } } @@ -360,6 +373,7 @@ iterable_sub_enum! { EcDhBrainpoolP256R1, EcDhBrainpoolP384R1, EcDhBrainpoolP512R1, + EcDhSecp256k1, } } @@ -419,6 +433,7 @@ iterable_sub_enum! { EcDsaBrainpoolP256R1, EcDsaBrainpoolP384R1, EcDsaBrainpoolP512R1, + EcDsaSecp256k1, } } @@ -594,6 +609,8 @@ pub enum CurveAlgo { EcDsaBrainpoolP384R1, EcDhBrainpoolP512R1, EcDsaBrainpoolP512R1, + EcDsaSecp256k1, + EcDhSecp256k1, X255, Ed255, } @@ -609,6 +626,7 @@ impl CurveAlgo { Self::EcDsaBrainpoolP512R1 | Self::EcDhBrainpoolP512R1 => Mechanism::BrainpoolP512R1, Self::X255 => Mechanism::X255, Self::Ed255 => Mechanism::Ed255, + Self::EcDsaSecp256k1 | Self::EcDhSecp256k1 => Mechanism::Secp256k1, } } @@ -620,6 +638,7 @@ impl CurveAlgo { Self::EcDsaBrainpoolP256R1 | Self::EcDhBrainpoolP256R1 => 0x04, Self::EcDsaBrainpoolP384R1 | Self::EcDhBrainpoolP384R1 => 0x04, Self::EcDsaBrainpoolP512R1 | Self::EcDhBrainpoolP512R1 => 0x04, + Self::EcDsaSecp256k1 | Self::EcDhSecp256k1 => 0x04, Self::X255 | Self::Ed255 => 0x40, } } diff --git a/tests/brainpool-p512r1.rs b/tests/brainpool-p512r1.rs index 2f4390e..e18a26c 100644 --- a/tests/brainpool-p512r1.rs +++ b/tests/brainpool-p512r1.rs @@ -7,6 +7,6 @@ mod gpg; use test_log::test; #[test] -fn p521_gpg_hardware() { +fn brainpool512_gpg_hardware() { gpg::gpg_test(gpg::KeyAlgo::BrainpoolP512R1); } diff --git a/tests/gpg/mod.rs b/tests/gpg/mod.rs index ca39156..8a1b4c3 100644 --- a/tests/gpg/mod.rs +++ b/tests/gpg/mod.rs @@ -122,6 +122,8 @@ pub enum KeyType { BrainpoolP384R1NoAut, BrainpoolP512R1, BrainpoolP512R1NoAut, + Secp256k1, + Secp256k1NoAut, } #[allow(unused)] @@ -225,6 +227,20 @@ pub fn gpg_status(key: KeyType, sign_count: usize) -> Vec<&'static str> { "fpr:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}::", "grp:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:[0]{40}:", ), + KeyType::Secp256k1 => ( + r"keyattr:1:19:secp256k1:", + r"keyattr:2:18:secp256k1:", + r"keyattr:3:19:secp256k1:", + "fpr:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:", + "grp:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:", + ), + KeyType::Secp256k1NoAut => ( + r"keyattr:1:19:secp256k1:", + r"keyattr:2:18:secp256k1:", + r"keyattr:3:1:2048:", + "fpr:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}::", + "grp:[0-9a-zA-Z]{40}:[0-9a-zA-Z]{40}:[0]{40}:", + ), KeyType::Rsa2048 => ( r"keyattr:1:1:2048:", r"keyattr:2:1:2048:", @@ -554,6 +570,7 @@ pub enum KeyAlgo { BrainpoolP256R1, BrainpoolP384R1, BrainpoolP512R1, + Secp256k1, } impl KeyAlgo { @@ -612,6 +629,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => Self::_generate_for_key("2", "6", temp_name, temp_email), Self::BrainpoolP384R1 => Self::_generate_for_key("2", "7", temp_name, temp_email), Self::BrainpoolP512R1 => Self::_generate_for_key("2", "8", temp_name, temp_email), + Self::Secp256k1 => Self::_generate_for_key("2", "9", temp_name, temp_email), } } @@ -663,6 +681,9 @@ impl KeyAlgo { Self::BrainpoolP512R1 => { vec!["9", "8", "0", temp_name, temp_email, "no comment", "", ""] } + Self::Secp256k1 => { + vec!["9", "9", "0", temp_name, temp_email, "no comment", "", ""] + } } } @@ -698,7 +719,8 @@ impl KeyAlgo { | Self::P521 | Self::BrainpoolP256R1 | Self::BrainpoolP384R1 - | Self::BrainpoolP512R1 => true, + | Self::BrainpoolP512R1 + | Self::Secp256k1 => true, Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => false, } } @@ -711,6 +733,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => "brainpoolP256r1:23", Self::BrainpoolP384R1 => "brainpoolP384r1:23", Self::BrainpoolP512R1 => "brainpoolP512r1:23", + Self::Secp256k1 => "secp256k1:", Self::Cv25519 => "ed25519:", Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => ":23", } @@ -724,6 +747,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => "brainpoolP256r1", Self::BrainpoolP384R1 => "brainpoolP384r1", Self::BrainpoolP512R1 => "brainpoolP512r1", + Self::Secp256k1 => "secp256k1", Self::Cv25519 => "cv25519", Self::Rsa2048 => "rsa2048", Self::Rsa3072 => "rsa3072", @@ -739,6 +763,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => "brainpoolP256r1", Self::BrainpoolP384R1 => "brainpoolP384r1", Self::BrainpoolP512R1 => "brainpoolP512r1", + Self::Secp256k1 => "secp256k1", Self::Cv25519 => "cv25519", Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => ":23", } @@ -751,7 +776,8 @@ impl KeyAlgo { | Self::P521 | Self::BrainpoolP256R1 | Self::BrainpoolP384R1 - | Self::BrainpoolP512R1 => "19", + | Self::BrainpoolP512R1 + | Self::Secp256k1 => "19", Self::Cv25519 => "22", Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => "1", } @@ -764,7 +790,8 @@ impl KeyAlgo { | Self::P521 | Self::BrainpoolP256R1 | Self::BrainpoolP384R1 - | Self::BrainpoolP512R1 => "ECDSA", + | Self::BrainpoolP512R1 + | Self::Secp256k1 => "ECDSA", Self::Cv25519 => "EDDSA", Self::Rsa2048 => "RSA key [0-9A-F]{40}", Self::Rsa3072 => "RSA key [0-9A-F]{40}", @@ -779,7 +806,8 @@ impl KeyAlgo { | Self::P521 | Self::BrainpoolP256R1 | Self::BrainpoolP384R1 - | Self::BrainpoolP512R1 => "18", + | Self::BrainpoolP512R1 + | Self::Secp256k1 => "18", Self::Cv25519 => "18", Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => "1", } @@ -799,7 +827,8 @@ impl KeyAlgo { | Self::P521 | Self::BrainpoolP256R1 | Self::BrainpoolP384R1 - | Self::BrainpoolP512R1 => { + | Self::BrainpoolP512R1 + | Self::Secp256k1 => { let mut ask = attr_ec_ask(); ask.push(r"\[GNUPG:\] GET_LINE cardedit.prompt"); ask @@ -819,6 +848,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => KeyType::BrainpoolP256R1, Self::BrainpoolP384R1 => KeyType::BrainpoolP384R1, Self::BrainpoolP512R1 => KeyType::BrainpoolP512R1, + Self::Secp256k1 => KeyType::Secp256k1, } } @@ -835,6 +865,7 @@ impl KeyAlgo { Self::BrainpoolP256R1 => KeyType::BrainpoolP256R1NoAut, Self::BrainpoolP384R1 => KeyType::BrainpoolP384R1NoAut, Self::BrainpoolP512R1 => KeyType::BrainpoolP512R1NoAut, + Self::Secp256k1 => KeyType::Secp256k1NoAut, } } } diff --git a/tests/secp256k1-import.rs b/tests/secp256k1-import.rs new file mode 100644 index 0000000..768fdf0 --- /dev/null +++ b/tests/secp256k1-import.rs @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Nitrokey GmbH +// SPDX-License-Identifier: LGPL-3.0-only +#![cfg(feature = "dangerous-test-real-card")] + +mod gpg; + +use test_log::test; + +#[test] +fn secp256k1_import_gpg_hardware() { + gpg::gpg_test_import(gpg::KeyAlgo::Secp256k1); +} diff --git a/tests/secp256k1.rs b/tests/secp256k1.rs new file mode 100644 index 0000000..c21bedf --- /dev/null +++ b/tests/secp256k1.rs @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Nitrokey GmbH +// SPDX-License-Identifier: LGPL-3.0-only +#![cfg(feature = "dangerous-test-real-card")] + +mod gpg; + +use test_log::test; + +#[test] +fn secp256k1_gpg_hardware() { + gpg::gpg_test(gpg::KeyAlgo::Secp256k1); +}