From d625823f28367406c4b58b6fe23725355d19a240 Mon Sep 17 00:00:00 2001 From: Anton Burticica Date: Fri, 22 Nov 2024 21:08:04 +0200 Subject: [PATCH 1/2] Support for EC keys, fix Attributes processing --- Cargo.lock | 1 + native-pkcs11-core/Cargo.toml | 2 + native-pkcs11-core/src/object.rs | 123 +++++++++++++++++++++--------- native-pkcs11-traits/src/lib.rs | 2 +- native-pkcs11/src/lib.rs | 18 +++-- native-pkcs11/src/object_store.rs | 4 +- 6 files changed, 107 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4ed3d21..fb701572 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,6 +292,7 @@ dependencies = [ "pkcs11-sys", "pkcs8", "serial_test", + "spki", "strum", "strum_macros", "thiserror 2.0.11", diff --git a/native-pkcs11-core/Cargo.toml b/native-pkcs11-core/Cargo.toml index 119f6037..08906717 100644 --- a/native-pkcs11-core/Cargo.toml +++ b/native-pkcs11-core/Cargo.toml @@ -11,6 +11,8 @@ license.workspace = true [dependencies] der = "0.7.9" native-pkcs11-traits = { version = "0.2.0", path = "../native-pkcs11-traits" } +spki = "0.7" +der = "0.7" pkcs1 = { version = "0.7.5", default-features = false } pkcs11-sys = { version = "0.2.24", path = "../pkcs11-sys" } pkcs8 = "0.10.2" diff --git a/native-pkcs11-core/src/object.rs b/native-pkcs11-core/src/object.rs index 0507b97b..3471e023 100644 --- a/native-pkcs11-core/src/object.rs +++ b/native-pkcs11-core/src/object.rs @@ -23,7 +23,11 @@ use native_pkcs11_traits::{ PrivateKey, PublicKey, }; + +use spki::SubjectPublicKeyInfoRef; use pkcs1::{der::Decode, RsaPublicKey}; +use der::{asn1::OctetString, asn1::ObjectIdentifier, Encode}; + use pkcs11_sys::{ CKC_X_509, CKK_EC, @@ -74,6 +78,30 @@ impl Clone for Object { } } +fn extract_ec_params(der_bytes: &[u8]) -> Option<(Vec, Vec)> { + let spki: SubjectPublicKeyInfoRef<'_> = SubjectPublicKeyInfoRef::try_from(der_bytes).unwrap(); + // For EC keys, the algorithm parameters contain the curve OID + // For EC keys, the subject public key is the EC point + Some(( + ObjectIdentifier::from_bytes(spki.algorithm.parameters.unwrap().value()).unwrap().to_der().unwrap(), + OctetString::new(spki.subject_public_key.raw_bytes()).unwrap().to_der().unwrap(), + )) +} + +fn extract_rsa_params(der_bytes: &[u8]) -> Option<(Vec, Vec, u64)> { + // Parse the DER-encoded SPKI + let spki: SubjectPublicKeyInfoRef<'_> = SubjectPublicKeyInfoRef::try_from(der_bytes).unwrap(); + // Parse the RSA public key bytes from the SPKI + let rsa_pubkey = RsaPublicKey::from_der(spki.subject_public_key.raw_bytes()).ok()?; + let modulus = rsa_pubkey.modulus.as_bytes(); + + Some(( + modulus.to_vec(), + rsa_pubkey.public_exponent.as_bytes().to_vec(), + (modulus.len() * 8) as u64, + )) +} + impl Object { pub fn attribute(&self, type_: AttributeType) -> Option { match self { @@ -102,7 +130,25 @@ impl Object { AttributeType::Class => Some(Attribute::Class(CKO_PRIVATE_KEY)), AttributeType::Decrypt => Some(Attribute::Decrypt(false)), AttributeType::Derive => Some(Attribute::Derive(false)), - AttributeType::EcParams => Some(Attribute::EcParams(P256_OID.to_der().ok()?)), + AttributeType::EcParams | AttributeType::EcPoint => { + if private_key.algorithm() != KeyAlgorithm::Ecc { + return None; + } + private_key + .find_public_key(backend()) + .ok() + .flatten() + .and_then(|public_key| { + let der_bytes = public_key.to_der(); + extract_ec_params(&der_bytes).map(|(params, point)| { + match type_ { + AttributeType::EcParams => Attribute::EcParams(params), + AttributeType::EcPoint => Attribute::EcPoint(point), + _ => unreachable!() + } + }) + }) + } AttributeType::Extractable => Some(Attribute::Extractable(false)), AttributeType::Id => Some(Attribute::Id(private_key.public_key_hash())), AttributeType::KeyType => Some(Attribute::KeyType(match private_key.algorithm() { @@ -111,34 +157,28 @@ impl Object { })), AttributeType::Label => Some(Attribute::Label(private_key.label())), AttributeType::Local => Some(Attribute::Local(false)), - AttributeType::Modulus => { - let modulus = private_key + AttributeType::Modulus | AttributeType::ModulusBits | AttributeType::PublicExponent => { + if private_key.algorithm() != KeyAlgorithm::Rsa { + return None; + } + private_key .find_public_key(backend()) .ok() .flatten() .and_then(|public_key| { - let der = public_key.to_der(); - RsaPublicKey::from_der(&der) - .map(|pk| pk.modulus.as_bytes().to_vec()) - .ok() - }); - modulus.map(Attribute::Modulus) + let der_bytes = public_key.to_der(); + extract_rsa_params(&der_bytes).map(|(modulus, exponent, bits)| { + match type_ { + AttributeType::Modulus => Attribute::Modulus(modulus), + AttributeType::ModulusBits => Attribute::ModulusBits(bits), + AttributeType::PublicExponent => Attribute::PublicExponent(exponent), + _ => unreachable!() + } + }) + }) } AttributeType::NeverExtractable => Some(Attribute::NeverExtractable(true)), AttributeType::Private => Some(Attribute::Private(true)), - AttributeType::PublicExponent => { - let public_exponent = private_key - .find_public_key(backend()) - .ok() - .flatten() - .and_then(|public_key| { - let der = public_key.to_der(); - RsaPublicKey::from_der(&der) - .map(|pk| pk.public_exponent.as_bytes().to_vec()) - .ok() - }); - public_exponent.map(Attribute::PublicExponent) - } AttributeType::Sensitive => Some(Attribute::Sensitive(true)), AttributeType::Sign => Some(Attribute::Sign(true)), AttributeType::SignRecover => Some(Attribute::SignRecover(false)), @@ -160,32 +200,45 @@ impl Object { }, Object::PublicKey(pk) => match type_ { AttributeType::Class => Some(Attribute::Class(CKO_PUBLIC_KEY)), + AttributeType::Verify => Some(Attribute::Verify(true)), + AttributeType::VerifyRecover => Some(Attribute::VerifyRecover(false)), + AttributeType::Wrap => Some(Attribute::Wrap(false)), + AttributeType::Encrypt => Some(Attribute::Encrypt(false)), AttributeType::Derive => Some(Attribute::Derive(false)), AttributeType::Label => Some(Attribute::Label(pk.label())), AttributeType::Local => Some(Attribute::Local(false)), - AttributeType::Modulus => { - let key = pk.to_der(); - let key = RsaPublicKey::from_der(&key).unwrap(); - Some(Attribute::Modulus(key.modulus.as_bytes().to_vec())) - } - AttributeType::PublicExponent => { - let key = pk.to_der(); - let key = RsaPublicKey::from_der(&key).unwrap(); - Some(Attribute::Modulus(key.public_exponent.as_bytes().to_vec())) + AttributeType::Modulus | AttributeType::ModulusBits | AttributeType::PublicExponent => { + if pk.algorithm() != KeyAlgorithm::Rsa { + return None; + } + let der_bytes = pk.to_der(); + extract_rsa_params(&der_bytes).map(|(modulus, exponent, bits)| { + match type_ { + AttributeType::Modulus => Attribute::Modulus(modulus), + AttributeType::ModulusBits => Attribute::ModulusBits(bits), + AttributeType::PublicExponent => Attribute::PublicExponent(exponent), + _ => unreachable!() + } + }) } AttributeType::KeyType => Some(Attribute::KeyType(match pk.algorithm() { native_pkcs11_traits::KeyAlgorithm::Rsa => CKK_RSA, native_pkcs11_traits::KeyAlgorithm::Ecc => CKK_EC, })), AttributeType::Id => Some(Attribute::Id(pk.public_key_hash())), - AttributeType::EcPoint => { + AttributeType::EcParams | AttributeType::EcPoint => { if pk.algorithm() != KeyAlgorithm::Ecc { return None; } - let wrapped = OctetString::new(pk.to_der()).ok()?; - Some(Attribute::EcPoint(wrapped.to_der().ok()?)) + let der_bytes = pk.to_der(); + extract_ec_params(&der_bytes).map(|(params, point)| { + match type_ { + AttributeType::EcParams => Attribute::EcParams(params), + AttributeType::EcPoint => Attribute::EcPoint(point), + _ => unreachable!() + } + }) } - AttributeType::EcParams => Some(Attribute::EcParams(P256_OID.to_der().ok()?)), _ => { debug!("public_key: type_ unimplemented: {:?}", type_); None diff --git a/native-pkcs11-traits/src/lib.rs b/native-pkcs11-traits/src/lib.rs index 58fc0ebe..cf1b0716 100644 --- a/native-pkcs11-traits/src/lib.rs +++ b/native-pkcs11-traits/src/lib.rs @@ -21,7 +21,7 @@ use std::{ use x509_cert::der::Decode; pub type Result = std::result::Result>; -pub type Digest = [u8; 20]; +pub type Digest = [u8; 64]; // The Backend is first staged so it can be stored in a Box. This // allows the Backend to be reference with `&'static`. diff --git a/native-pkcs11/src/lib.rs b/native-pkcs11/src/lib.rs index d51b4ed7..aa946dd3 100644 --- a/native-pkcs11/src/lib.rs +++ b/native-pkcs11/src/lib.rs @@ -35,7 +35,7 @@ use std::{ }; use native_pkcs11_core::{ - attribute::{Attribute, Attributes}, + attribute::{Attribute, AttributeType, Attributes}, mechanism::{parse_mechanism, SUPPORTED_SIGNATURE_MECHANISMS}, object::{self, Object}, }; @@ -600,10 +600,18 @@ cryptoki_fn!( }; let mut result = Ok(()); for attribute in template.iter_mut() { - let type_ = attribute - .type_ - .try_into() - .map_err(|_| Error::AttributeTypeInvalid(attribute.type_))?; + let type_ = match AttributeType::try_from(attribute.type_) { + Ok(t) => t, + Err(_) => { + tracing::debug!( + type_ = ?attribute.type_, + "Unsupported attribute type - marking as unavailable" + ); + attribute.ulValueLen = CK_UNAVAILABLE_INFORMATION; + // result = Err(Error::AttributeTypeInvalid(attribute.type_)); + continue; + } + }; if let Some(value) = object.attribute(type_) { let value = value.as_raw_value(); attribute.ulValueLen = value.len() as CK_ULONG; diff --git a/native-pkcs11/src/object_store.rs b/native-pkcs11/src/object_store.rs index 48af12fb..8c8aa1e5 100644 --- a/native-pkcs11/src/object_store.rs +++ b/native-pkcs11/src/object_store.rs @@ -171,8 +171,8 @@ impl ObjectStore { } fn find_with_backend_all_public_keys(&mut self) -> Result<()> { - for private_key in backend().find_all_private_keys()? { - self.insert(Object::PrivateKey(private_key)); + for public_key in backend().find_all_public_keys()? { + self.insert(Object::PublicKey(public_key)); } Ok(()) } From 2c5b44ec1c13b492417dd8a5825e1741aa2449b0 Mon Sep 17 00:00:00 2001 From: Anton Burticica Date: Tue, 14 Jan 2025 21:21:06 +0200 Subject: [PATCH 2/2] Support for EC keys, fix Attributes processing --- native-pkcs11-core/Cargo.toml | 1 - native-pkcs11-core/src/object.rs | 66 +++++++++++++++++--------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/native-pkcs11-core/Cargo.toml b/native-pkcs11-core/Cargo.toml index 08906717..96a8910f 100644 --- a/native-pkcs11-core/Cargo.toml +++ b/native-pkcs11-core/Cargo.toml @@ -12,7 +12,6 @@ license.workspace = true der = "0.7.9" native-pkcs11-traits = { version = "0.2.0", path = "../native-pkcs11-traits" } spki = "0.7" -der = "0.7" pkcs1 = { version = "0.7.5", default-features = false } pkcs11-sys = { version = "0.2.24", path = "../pkcs11-sys" } pkcs8 = "0.10.2" diff --git a/native-pkcs11-core/src/object.rs b/native-pkcs11-core/src/object.rs index 3471e023..e5fd186d 100644 --- a/native-pkcs11-core/src/object.rs +++ b/native-pkcs11-core/src/object.rs @@ -14,7 +14,10 @@ use std::{ffi::CString, fmt::Debug, sync::Arc}; -use der::{asn1::OctetString, Encode}; +use der::{ + asn1::{ObjectIdentifier, OctetString}, + Encode, +}; use native_pkcs11_traits::{ backend, Certificate, @@ -23,11 +26,7 @@ use native_pkcs11_traits::{ PrivateKey, PublicKey, }; - -use spki::SubjectPublicKeyInfoRef; use pkcs1::{der::Decode, RsaPublicKey}; -use der::{asn1::OctetString, asn1::ObjectIdentifier, Encode}; - use pkcs11_sys::{ CKC_X_509, CKK_EC, @@ -39,6 +38,7 @@ use pkcs11_sys::{ CK_CERTIFICATE_CATEGORY_UNSPECIFIED, CK_PROFILE_ID, }; +use spki::SubjectPublicKeyInfoRef; use tracing::debug; use crate::attribute::{Attribute, AttributeType, Attributes}; @@ -83,8 +83,14 @@ fn extract_ec_params(der_bytes: &[u8]) -> Option<(Vec, Vec)> { // For EC keys, the algorithm parameters contain the curve OID // For EC keys, the subject public key is the EC point Some(( - ObjectIdentifier::from_bytes(spki.algorithm.parameters.unwrap().value()).unwrap().to_der().unwrap(), - OctetString::new(spki.subject_public_key.raw_bytes()).unwrap().to_der().unwrap(), + ObjectIdentifier::from_bytes(spki.algorithm.parameters.unwrap().value()) + .unwrap() + .to_der() + .unwrap(), + OctetString::new(spki.subject_public_key.raw_bytes()) + .unwrap() + .to_der() + .unwrap(), )) } @@ -140,12 +146,10 @@ impl Object { .flatten() .and_then(|public_key| { let der_bytes = public_key.to_der(); - extract_ec_params(&der_bytes).map(|(params, point)| { - match type_ { - AttributeType::EcParams => Attribute::EcParams(params), - AttributeType::EcPoint => Attribute::EcPoint(point), - _ => unreachable!() - } + extract_ec_params(&der_bytes).map(|(params, point)| match type_ { + AttributeType::EcParams => Attribute::EcParams(params), + AttributeType::EcPoint => Attribute::EcPoint(point), + _ => unreachable!(), }) }) } @@ -157,7 +161,9 @@ impl Object { })), AttributeType::Label => Some(Attribute::Label(private_key.label())), AttributeType::Local => Some(Attribute::Local(false)), - AttributeType::Modulus | AttributeType::ModulusBits | AttributeType::PublicExponent => { + AttributeType::Modulus + | AttributeType::ModulusBits + | AttributeType::PublicExponent => { if private_key.algorithm() != KeyAlgorithm::Rsa { return None; } @@ -171,8 +177,10 @@ impl Object { match type_ { AttributeType::Modulus => Attribute::Modulus(modulus), AttributeType::ModulusBits => Attribute::ModulusBits(bits), - AttributeType::PublicExponent => Attribute::PublicExponent(exponent), - _ => unreachable!() + AttributeType::PublicExponent => { + Attribute::PublicExponent(exponent) + } + _ => unreachable!(), } }) }) @@ -207,18 +215,18 @@ impl Object { AttributeType::Derive => Some(Attribute::Derive(false)), AttributeType::Label => Some(Attribute::Label(pk.label())), AttributeType::Local => Some(Attribute::Local(false)), - AttributeType::Modulus | AttributeType::ModulusBits | AttributeType::PublicExponent => { + AttributeType::Modulus + | AttributeType::ModulusBits + | AttributeType::PublicExponent => { if pk.algorithm() != KeyAlgorithm::Rsa { return None; } let der_bytes = pk.to_der(); - extract_rsa_params(&der_bytes).map(|(modulus, exponent, bits)| { - match type_ { - AttributeType::Modulus => Attribute::Modulus(modulus), - AttributeType::ModulusBits => Attribute::ModulusBits(bits), - AttributeType::PublicExponent => Attribute::PublicExponent(exponent), - _ => unreachable!() - } + extract_rsa_params(&der_bytes).map(|(modulus, exponent, bits)| match type_ { + AttributeType::Modulus => Attribute::Modulus(modulus), + AttributeType::ModulusBits => Attribute::ModulusBits(bits), + AttributeType::PublicExponent => Attribute::PublicExponent(exponent), + _ => unreachable!(), }) } AttributeType::KeyType => Some(Attribute::KeyType(match pk.algorithm() { @@ -231,12 +239,10 @@ impl Object { return None; } let der_bytes = pk.to_der(); - extract_ec_params(&der_bytes).map(|(params, point)| { - match type_ { - AttributeType::EcParams => Attribute::EcParams(params), - AttributeType::EcPoint => Attribute::EcPoint(point), - _ => unreachable!() - } + extract_ec_params(&der_bytes).map(|(params, point)| match type_ { + AttributeType::EcParams => Attribute::EcParams(params), + AttributeType::EcPoint => Attribute::EcPoint(point), + _ => unreachable!(), }) } _ => {