Skip to content

Commit

Permalink
Support for EC keys, fix Attributes processing
Browse files Browse the repository at this point in the history
  • Loading branch information
ya-mouse committed Nov 22, 2024
1 parent 93387f1 commit 4e6bc70
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 50 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions native-pkcs11-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ p256 = { version = "0.13.2", default-features = false, features = [
"pkcs8",
"std",
] }
spki = "0.7"
der = "0.7"
pkcs1 = { version = "0.7.5", default-features = false }
pkcs11-sys = { version = "0.2.0", path = "../pkcs11-sys" }
strum = "0.26"
Expand Down
129 changes: 87 additions & 42 deletions native-pkcs11-core/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ use native_pkcs11_traits::{
PrivateKey,
PublicKey,
};
use p256::pkcs8::{
der::{asn1::OctetString, Encode},
AssociatedOid,
};

use spki::SubjectPublicKeyInfoRef;
use pkcs1::{der::Decode, RsaPublicKey};
use der::{asn1::OctetString, asn1::ObjectIdentifier, Encode};

use pkcs11_sys::{
CKC_X_509,
CKK_EC,
Expand Down Expand Up @@ -74,6 +74,30 @@ impl Clone for Object {
}
}

fn extract_ec_params(der_bytes: &[u8]) -> Option<(Vec<u8>, Vec<u8>)> {
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<u8>, Vec<u8>, 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<Attribute> {
match self {
Expand Down Expand Up @@ -102,8 +126,24 @@ 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::NistP256::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())),
Expand All @@ -113,34 +153,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)),
Expand All @@ -162,33 +196,44 @@ 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()?))
}
AttributeType::EcParams => {
Some(Attribute::EcParams(p256::NistP256::OID.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!()
}
})
}
_ => {
debug!("public_key: type_ unimplemented: {:?}", type_);
Expand Down
2 changes: 1 addition & 1 deletion native-pkcs11-traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::{
use x509_cert::der::Decode;

pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
pub type Digest = [u8; 20];
pub type Digest = [u8; 64];

// The Backend is first staged so it can be stored in a Box<dyn Backend>. This
// allows the Backend to be reference with `&'static`.
Expand Down
18 changes: 13 additions & 5 deletions native-pkcs11/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions native-pkcs11/src/object_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down

0 comments on commit 4e6bc70

Please sign in to comment.