feat: update pkcs11 piv

This commit is contained in:
2024-07-06 21:42:41 +08:00
parent 1b174db255
commit a7bfda9cbf
5 changed files with 92 additions and 422 deletions

4
Cargo.lock generated
View File

@@ -563,9 +563,9 @@ dependencies = [
[[package]]
name = "num-bigint"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",

View File

@@ -16,7 +16,7 @@ use std::sync::Arc;
use tracing::instrument;
use native_pkcs11_traits::Backend;
use native_pkcs11_traits::{Backend, KeySearchOptions};
use native_pkcs11_traits::Certificate as P11Certificate;
use native_pkcs11_traits::KeyAlgorithm as P11KeyAlgorithm;
use native_pkcs11_traits::KeySearchOptions as P11KeySearchOptions;
@@ -43,13 +43,6 @@ impl Backend for YubikeyPivBackend {
&self,
) -> P11Result<Vec<Box<dyn P11Certificate>>> {
Ok(vec![])
// let certs = find_all_certificates()?
// .into_iter()
// .map(YubikeyPivCertificate::new)
// .filter_map(Result::ok)
// .map(|cert| Box::new(cert) as _)
// .collect();
// Ok(certs)
}
#[instrument]
@@ -57,42 +50,11 @@ impl Backend for YubikeyPivBackend {
&self,
query: P11KeySearchOptions,
) -> P11Result<Option<Arc<dyn P11PrivateKey>>> {
match query {
KeySearchOptions::Label(label) => {}
KeySearchOptions::PublicKeyHash(public_key_hash) => {}
}
Ok(None)
// let mut pubkeys_by_pubkey_hash: HashMap<Vec<u8>, SecKey> =
// HashMap::from_iter(find_all_certificates()?.into_iter().filter_map(|c| {
// c.certificate()
// .ok()
// .and_then(|cert| cert.public_key().ok())
// .and_then(|pk| pk.application_label().map(|pubkey_hash| (pubkey_hash, pk)))
// }));
//
// let mut find_pubkey_for_seckey = |sec_key: &SecKey| -> Option<YubikeyPivPublicKey> {
// sec_key
// .application_label()
// .and_then(|pubkey_hash| pubkeys_by_pubkey_hash.remove(&pubkey_hash))
// // TODO(kcking): populate label if searching by label
// .and_then(|sec_key| YubikeyPivPublicKey::new(sec_key, "").ok())
// };
// let opt_key = match query {
// P11KeySearchOptions::Label(label) => {
// find_key(KeyClass::private(), &label)
// .ok()
// .map(|sec_key| {
// let cert = find_pubkey_for_seckey(&sec_key);
// YubikeyPivPrivateKey::new(sec_key, label, cert)
// })
// .transpose()?
// }
// P11KeySearchOptions::PublicKeyHash(public_key_hash) => {
// find_key2(KeyClass::private(), &public_key_hash)?
// .map(|sec_key| {
// let cert = find_pubkey_for_seckey(&sec_key);
// YubikeyPivPrivateKey::new(sec_key, "", cert)
// })
// .transpose()?
// }
// };
// Ok(opt_key.map(|sec_key| Arc::new(sec_key) as _))
}
#[instrument]
@@ -100,68 +62,23 @@ impl Backend for YubikeyPivBackend {
&self,
query: P11KeySearchOptions,
) -> P11Result<Option<Box<dyn P11PublicKey>>> {
match query {
KeySearchOptions::Label(label) => {}
KeySearchOptions::PublicKeyHash(public_key_hash) => {}
}
Ok(None)
// let opt_key = match query {
// P11KeySearchOptions::Label(label) => {
// find_key(KeyClass::public(), &label)
// .ok()
// .map(|sec_key| YubikeyPivPublicKey::new(sec_key, label))
// .transpose()?
// }
// P11KeySearchOptions::PublicKeyHash(public_key_hash) => {
// find_key2(KeyClass::public(), &public_key_hash)?
// .map(|sec_key| YubikeyPivPublicKey::new(sec_key, ""))
// .transpose()?
// }
// };
// Ok(opt_key.map(|sec_key| Box::new(sec_key) as _))
}
fn find_all_private_keys(
&self,
) -> P11Result<Vec<Arc<dyn P11PrivateKey>>> {
Ok(vec![])
// let sec_keys = find_all_keys(KeyClass::private())?;
// let keys = sec_keys
// .into_iter()
// .filter_map(|sec_key| {
// let label: Option<String> = sec_key
// .attributes()
// .find(unsafe { kSecAttrLabel }.to_void())
// .map(|label| {
// unsafe { CFString::wrap_under_get_rule(label.cast()) }.to_string()
// });
// let label: String = label.unwrap_or_default();
//
// YubikeyPivPrivateKey::new(sec_key, label, None).ok()
// })
// .map(|k| Arc::new(k) as _);
//
// Ok(keys.collect())
}
fn find_all_public_keys(
&self,
) -> P11Result<Vec<Arc<dyn P11PublicKey>>> {
Ok(vec![])
// let sec_keys = find_all_keys(KeyClass::public())?;
//
// let keys = sec_keys
// .into_iter()
// .filter_map(|sec_key| {
// let label: Option<String> = sec_key
// .attributes()
// .find(unsafe { kSecAttrLabel }.to_void())
// .map(|label| {
// unsafe { CFString::wrap_under_get_rule(label.cast()) }.to_string()
// });
// let label: String = label.unwrap_or_default();
//
// YubikeyPivPublicKey::new(sec_key, label).ok()
// })
// .map(|k| Arc::new(k) as _);
//
// Ok(keys.collect())
}
#[instrument]

View File

@@ -12,78 +12,35 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{
str::FromStr,
time::{Duration, SystemTime},
};
use rsa::{pkcs1::DecodeRsaPublicKey, pkcs8::AssociatedOid};
use security_framework::{
certificate::SecCertificate,
identity::SecIdentity,
item::{add_item, AddRef, ItemAddOptions, ItemClass, Reference},
key::SecKey,
os::macos::identity::SecIdentityExt,
};
use security_framework_sys::base::errSecItemNotFound;
use x509_cert::{
Certificate,
der::{
asn1::{GeneralizedTime, Ia5String, OctetString},
Decode,
Encode,
oid::ObjectIdentifier,
},
ext::{
Extension,
pkix::{
AuthorityKeyIdentifier,
BasicConstraints,
ExtendedKeyUsage,
KeyUsage,
KeyUsages,
name::GeneralName,
SubjectAltName,
SubjectKeyIdentifier,
},
},
name::{Name, RdnSequence},
serial_number::SerialNumber,
spki::{der::asn1::BitString, EncodePublicKey, SubjectPublicKeyInfo},
TbsCertificate,
time::Validity,
};
use std::fmt::Debug;
use native_pkcs11_traits::Certificate as P11Certificate;
use native_pkcs11_traits::random_label;
use native_pkcs11_traits::PublicKey as P11PublicKey;
use crate::{
key::{Algorithm, YubikeyPivPublicKey},
Result,
};
use crate::key::YubikeyPivPublicKey;
pub struct YubikeyPivCertificate {
pub label: String,
pub identity: SecIdentity,
pub identity: String,
pub public_key: YubikeyPivPublicKey,
certificate_der: Vec<u8>,
}
impl YubikeyPivCertificate {
pub fn new(identity: impl Into<SecIdentity>) -> Result<Self> {
let identity: SecIdentity = identity.into();
let label = identity.certificate().unwrap().subject_summary();
let pk = identity.certificate()?.public_key()?;
Ok(Self {
certificate_der: identity.certificate()?.to_der(),
label: label.clone(),
identity,
public_key: YubikeyPivPublicKey::new(pk, label)?,
})
}
// pub fn new(identity: impl Into<SecIdentity>) -> Result<Self> {
// let identity: SecIdentity = identity.into();
// let label = identity.certificate().unwrap().subject_summary();
// let pk = identity.certificate()?.public_key()?;
// Ok(Self {
// certificate_der: identity.certificate()?.to_der(),
// label: label.clone(),
// identity,
// public_key: YubikeyPivPublicKey::new(pk, label)?,
// })
// }
}
impl std::fmt::Debug for YubikeyPivCertificate {
impl Debug for YubikeyPivCertificate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("KeychainCertificate")
.field("label", &self.label)
@@ -97,57 +54,15 @@ impl P11Certificate for YubikeyPivCertificate {
self.label.to_string()
}
fn public_key(&self) -> &dyn native_pkcs11_traits::PublicKey {
&self.public_key
}
fn to_der(&self) -> Vec<u8> {
self.certificate_der.clone()
}
fn public_key(&self) -> &dyn P11PublicKey {
&self.public_key
}
fn delete(self: Box<Self>) {
let _ = self.identity.delete();
// yubikey-piv-pkcs11 just cannot delete certificate
}
}
pub fn import_certificate(der: &[u8]) -> Result<SecCertificate> {
Err("")?
// let cert = SecCertificate::from_der(der)?;
//
// let add_params = ItemAddOptions::new(security_framework::item::ItemAddValue::Ref(
// AddRef::Certificate(cert.clone()),
// ))
// .set_location(keychain::location()?)
// .set_label(cert.subject_summary())
// .to_dictionary();
// add_item(add_params)?;
//
// Ok(cert)
}
pub fn find_certificate(pub_key_hash: &[u8]) -> Result<Option<SecIdentity>> {
Ok(None)
// let results = crate::piv::keychain::item_search_options()?
// .load_refs(true)
// .class(ItemClass::certificate())
// .pub_key_hash(pub_key_hash)
// .search()?;
//
// if results.is_empty() {
// return Ok(None);
// }
//
// let cert = match results.into_iter().next().ok_or("certificate not found")? {
// security_framework::item::SearchResult::Ref(Reference::Certificate(certificate)) => {
// certificate
// }
// _ => return Err("no key ref")?,
// };
//
// Ok(Some(SecIdentity::with_certificate(&[], &cert)?))
}
pub fn random_serial_number() -> [u8; 16] {
use rand::Rng;
rand::thread_rng().gen::<u128>().to_be_bytes()
}

View File

@@ -14,76 +14,18 @@
use std::fmt::Debug;
use core_foundation::base::ToVoid;
use security_framework::{
item::{ItemClass, KeyClass, Limit, Reference},
key::SecKey,
};
// TODO(bweeks,kcking): remove dependency on security-framework-sys crate.
use security_framework_sys::item::{
kSecAttrKeyType,
kSecAttrKeyTypeEC,
kSecAttrKeyTypeRSA,
kSecAttrTokenID,
};
use security_framework::key::SecKey;
use tracing::instrument;
use native_pkcs11_traits::{KeyAlgorithm, PrivateKey, PublicKey, SignatureAlgorithm};
use native_pkcs11_traits::DigestType as P11DigestType;
use native_pkcs11_traits::{Backend, KeyAlgorithm, PrivateKey, PublicKey, SignatureAlgorithm};
use native_pkcs11_traits::Result as P11Result;
use crate::Result;
#[derive(Debug)]
pub enum Algorithm {
RSA,
ECC,
}
fn sigalg_to_seckeyalg(
signature_algorithm: &SignatureAlgorithm,
) -> Result<security_framework_sys::key::Algorithm> {
use security_framework_sys::key::Algorithm::*;
let alg = match signature_algorithm {
SignatureAlgorithm::Ecdsa => ECDSASignatureRFC4754,
SignatureAlgorithm::RsaRaw => RSASignatureRaw,
SignatureAlgorithm::RsaPkcs1v15Raw => RSASignatureDigestPKCS1v15Raw,
SignatureAlgorithm::RsaPkcs1v15Sha1 => {
RSASignatureMessagePKCS1v15SHA1
}
SignatureAlgorithm::RsaPkcs1v15Sha384 => {
RSASignatureMessagePKCS1v15SHA384
}
SignatureAlgorithm::RsaPkcs1v15Sha256 => {
RSASignatureMessagePKCS1v15SHA256
}
SignatureAlgorithm::RsaPkcs1v15Sha512 => {
RSASignatureMessagePKCS1v15SHA512
}
SignatureAlgorithm::RsaPss {
digest,
mask_generation_function,
salt_length,
} => {
// SecurityFramework only supports digest == mgf, salt_length == len(digest).
if digest != mask_generation_function || digest.digest_len() != *salt_length as usize {
return Err(crate::ErrorKind::UnsupportedSignatureAlgorithm(
signature_algorithm.clone(),
)
.into());
}
match mask_generation_function {
P11DigestType::Sha1 => RSASignatureDigestPSSSHA1,
P11DigestType::Sha224 => RSASignatureDigestPSSSHA224,
P11DigestType::Sha256 => RSASignatureDigestPSSSHA256,
P11DigestType::Sha384 => RSASignatureDigestPSSSHA384,
P11DigestType::Sha512 => RSASignatureDigestPSSSHA512,
}
}
};
Ok(alg)
}
#[derive(Debug)]
pub struct YubikeyPivPrivateKey {
sec_key: SecKey,
@@ -94,22 +36,22 @@ pub struct YubikeyPivPrivateKey {
}
impl YubikeyPivPrivateKey {
#[instrument]
pub fn new(
sec_key: SecKey,
label: impl Into<String> + Debug,
pub_key: Option<YubikeyPivPublicKey>,
) -> Result<Self> {
let label = label.into();
let public_key_hash = sec_key.application_label().ok_or("no application_label")?;
Ok(Self {
algorithm: sec_key_algorithm(&sec_key)?,
sec_key,
label,
public_key_hash,
pub_key,
})
}
// #[instrument]
// pub fn new(
// sec_key: SecKey,
// label: impl Into<String> + Debug,
// pub_key: Option<YubikeyPivPublicKey>,
// ) -> Result<Self> {
// let label = label.into();
// let public_key_hash = sec_key.application_label().ok_or("no application_label")?;
// Ok(Self {
// algorithm: sec_key_algorithm(&sec_key)?,
// sec_key,
// label,
// public_key_hash,
// pub_key,
// })
// }
}
impl PrivateKey for YubikeyPivPrivateKey {
@@ -129,62 +71,38 @@ impl PrivateKey for YubikeyPivPrivateKey {
algorithm: &SignatureAlgorithm,
data: &[u8],
) -> P11Result<Vec<u8>> {
let algorithm = sigalg_to_seckeyalg(algorithm)?;
Ok(self.sec_key.create_signature(algorithm, data.as_ref())?)
match algorithm {
SignatureAlgorithm::Ecdsa => {}
SignatureAlgorithm::RsaRaw => {}
SignatureAlgorithm::RsaPkcs1v15Raw => {}
SignatureAlgorithm::RsaPkcs1v15Sha1 => {}
SignatureAlgorithm::RsaPkcs1v15Sha384 => {}
SignatureAlgorithm::RsaPkcs1v15Sha256 => {}
SignatureAlgorithm::RsaPkcs1v15Sha512 => {}
SignatureAlgorithm::RsaPss { .. } => {}
}
// TODO sign data or hash??
Ok(vec![])
}
#[instrument]
fn delete(&self) {
let _ = self.sec_key.delete();
// yubikey-piv-pkcs11 just cannot delete private key
}
#[instrument]
fn algorithm(&self) -> KeyAlgorithm {
self.algorithm
}
fn find_public_key(
&self,
_backend: &dyn native_pkcs11_traits::Backend,
_backend: &dyn Backend,
) -> P11Result<Option<Box<dyn PublicKey>>> {
let sec_copy = self
.sec_key
.public_key()
.map(|sec_key| YubikeyPivPublicKey::new(sec_key, self.label()))
.transpose()
.ok()
.flatten()
.map(|key| Box::new(key) as _);
if sec_copy.is_some() {
return Ok(sec_copy);
}
Ok(self.pub_key.clone().map(|key| Box::new(key) as _))
Ok(None)
}
}
fn sec_key_algorithm(sec_key: &SecKey) -> Result<KeyAlgorithm> {
let attributes = sec_key.attributes();
if attributes
.find(unsafe { kSecAttrTokenID }.to_void())
.is_some()
{
// The only possible kSecAttrtokenID is kSecAttrTokenIDSecureEnclave.
//
// SecureEnclave keys do not have kSecAttrKeyType populated, but we can
// assume they are Ecc.
return Ok(KeyAlgorithm::Ecc);
}
let key_ty = sec_key
.attributes()
.find(unsafe { kSecAttrKeyType }.to_void())
.and_then(|key_type| match *key_type as *const _ {
ty if ty == unsafe { kSecAttrKeyTypeRSA } => Some(KeyAlgorithm::Rsa),
ty if ty == unsafe { kSecAttrKeyTypeEC } => Some(KeyAlgorithm::Ecc),
_ => None,
})
.ok_or("no key type")?;
Ok(key_ty)
}
#[derive(Debug, Clone)]
pub struct YubikeyPivPublicKey {
pub sec_key: SecKey,
@@ -195,20 +113,20 @@ pub struct YubikeyPivPublicKey {
}
impl YubikeyPivPublicKey {
#[instrument]
pub fn new(sec_key: SecKey, label: impl Into<String> + Debug) -> Result<Self> {
let der = sec_key
.external_representation()
.ok_or("no external representation")?;
let key_ty = sec_key_algorithm(&sec_key)?;
Ok(Self {
public_key_hash: sec_key.application_label().ok_or("no application_label")?,
sec_key,
label: label.into(),
der: der.to_vec(),
algorithm: key_ty,
})
}
// #[instrument]
// pub fn new(sec_key: SecKey, label: impl Into<String> + Debug) -> Result<Self> {
// let der = sec_key
// .external_representation()
// .ok_or("no external representation")?;
// let key_ty = sec_key_algorithm(&sec_key)?;
// Ok(Self {
// public_key_hash: sec_key.application_label().ok_or("no application_label")?,
// sec_key,
// label: label.into(),
// der: der.to_vec(),
// algorithm: key_ty,
// })
// }
}
impl PublicKey for YubikeyPivPublicKey {
@@ -230,15 +148,15 @@ impl PublicKey for YubikeyPivPublicKey {
#[instrument]
fn verify(
&self,
algorithm: &native_pkcs11_traits::SignatureAlgorithm,
algorithm: &SignatureAlgorithm,
data: &[u8],
signature: &[u8],
) -> P11Result<()> {
let algorithm = sigalg_to_seckeyalg(algorithm)?;
let result = self.sec_key.verify_signature(algorithm, data, signature)?;
if !result {
return Err("verify failed")?;
}
// let algorithm = sigalg_to_seckeyalg(algorithm)?;
// let result = self.sec_key.verify_signature(algorithm, data, signature)?;
// if !result {
// return Err("verify failed")?;
// }
Ok(())
}
@@ -250,77 +168,3 @@ impl PublicKey for YubikeyPivPublicKey {
self.algorithm
}
}
pub fn find_key(class: KeyClass, label: &str) -> Result<SecKey> {
Err("")?
// let results = crate::keychain::item_search_options()?
// .load_refs(true)
// .label(label)
// .class(ItemClass::key())
// .key_class(class)
// .limit(1)
// .search();
//
// let loaded_key = match results?.into_iter().next().ok_or("key not found")? {
// security_framework::item::SearchResult::Ref(Reference::Key(key)) => key,
// _ => return Err("no key ref")?,
// };
//
// Ok(loaded_key)
}
#[instrument]
pub fn find_key2(class: KeyClass, label: &[u8]) -> Result<Option<SecKey>> {
Ok(None)
// let results = crate::keychain::item_search_options()?
// .load_refs(true)
// .class(ItemClass::key())
// .key_class(class)
// .application_label(label)
// .limit(1)
// .search();
//
// let results = match results {
// Err(e) if e.code() == -25300 => return Ok(None),
// Err(e) => return Err(e)?,
// Ok(results) => results,
// };
//
// let loaded_key = results
// .into_iter()
// .next()
// .map(|key| match key {
// security_framework::item::SearchResult::Ref(Reference::Key(key)) => Ok::<_, &str>(key),
// _ => Err("no key ref")?,
// })
// .transpose()?;
//
// Ok(loaded_key)
}
#[instrument]
pub fn find_all_keys(key_class: KeyClass) -> Result<Vec<SecKey>> {
Ok(vec![])
// let results = crate::keychain::item_search_options()?
// .load_refs(true)
// .class(ItemClass::key())
// .key_class(key_class)
// .limit(Limit::All)
// .search();
//
// let results = match results {
// Err(e) if e.code() == -25300 => return Ok(vec![]),
// Err(e) => return Err(e)?,
// Ok(results) => results,
// };
//
// let keys = results
// .into_iter()
// .filter_map(|res| match res {
// security_framework::item::SearchResult::Ref(Reference::Key(key)) => Some(key),
// _ => None,
// })
// .collect();
//
// Ok(keys)
}

View File

@@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::fmt::Debug;
use std::fmt::{Debug, Formatter};
pub use backend::YubikeyPivBackend;
use core_foundation::error::CFError;
use native_pkcs11_traits::SignatureAlgorithm;
use thiserror::Error;
use tracing_error::SpanTrace;
pub use backend::YubikeyPivBackend;
use native_pkcs11_traits::SignatureAlgorithm;
mod backend;
pub mod certificate;
pub mod key;
@@ -32,7 +32,7 @@ pub struct Error {
}
impl Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{:?}", self.error)?;
self.context.fmt(f)
}
@@ -50,7 +50,7 @@ impl<E: Into<ErrorKind>> From<E> for Error {
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.error)?;
std::fmt::Display::fmt(&self.context, f)
}
@@ -80,12 +80,6 @@ pub enum ErrorKind {
UnsupportedSignatureAlgorithm(SignatureAlgorithm),
}
impl From<CFError> for ErrorKind {
fn from(e: CFError) -> Self {
ErrorKind::SecurityFramework(security_framework::base::Error::from_code(e.code() as i32))
}
}
impl From<&str> for ErrorKind {
fn from(s: &str) -> Self {
ErrorKind::Generic(s.to_string())