diff --git a/native-pkcs11-piv/src/piv/backend.rs b/native-pkcs11-piv/src/piv/backend.rs index 6d29049..d2cb2a1 100644 --- a/native-pkcs11-piv/src/piv/backend.rs +++ b/native-pkcs11-piv/src/piv/backend.rs @@ -29,12 +29,9 @@ use crate::{ find_all_keys, find_key, find_key2, - generate_key, - Algorithm, YubikeyPivPrivateKey, YubikeyPivPublicKey, }, - keychain, }; #[derive(Debug, Default)] @@ -130,16 +127,10 @@ impl Backend for YubikeyPivBackend { #[instrument] fn generate_key( &self, - algorithm: native_pkcs11_traits::KeyAlgorithm, - label: Option<&str>, + _algorithm: native_pkcs11_traits::KeyAlgorithm, + _label: Option<&str>, ) -> native_pkcs11_traits::Result> { - let alg = match algorithm { - native_pkcs11_traits::KeyAlgorithm::Rsa => Algorithm::RSA, - native_pkcs11_traits::KeyAlgorithm::Ecc => Algorithm::ECC, - }; - let label = label.unwrap_or(""); - Ok(generate_key(alg, label, Some(keychain::location()?)) - .map(|key| YubikeyPivPrivateKey::new(key, label, None).map(Arc::new))??) + Err("Generate key not supported, please use ykman, URL: https://hatter.in/ykman")? } fn find_all_private_keys( diff --git a/native-pkcs11-piv/src/piv/certificate.rs b/native-pkcs11-piv/src/piv/certificate.rs index 94848c3..0e03d7f 100644 --- a/native-pkcs11-piv/src/piv/certificate.rs +++ b/native-pkcs11-piv/src/piv/certificate.rs @@ -354,59 +354,3 @@ pub fn self_signed_certificate(key_algorithm: Algorithm, private_key: &SecKey) - Ok(cert.to_der()?) } - -#[cfg(test)] -mod test { - use native_pkcs11_traits::random_label; - use serial_test::serial; - - use super::*; - #[test] - #[serial] - #[ignore = "https://github.com/google/native-pkcs11/issues/302"] - fn test_self_signed_certificate() -> Result<()> { - use security_framework::item::{ItemClass, Limit}; - - use crate::key::generate_key; - - let label = random_label(); - let key = generate_key(Algorithm::RSA, &label, Some(keychain::location()?))?; - - let cert = self_signed_certificate(Algorithm::RSA, &key)?; - - let cert = import_certificate(&cert)?; - - // NOTE(kcking): Importing a certificate that has a private key already - // stored in the keychain will treat that certificate as an identity, even - // without calling import_identity. - // let identity = import_identity(&cert)?; - - // HACK(kcking): The macOS keychain takes some time to flush all of the updates - // such that they are visible to the next search query. - std::thread::sleep(std::time::Duration::from_secs(1)); - - assert!( - crate::piv::keychain::item_search_options()? - .class(ItemClass::identity()) - .limit(Limit::All) - .load_refs(true) - .search()? - .iter() - .any(|result| match result { - security_framework::item::SearchResult::Ref( - security_framework::item::Reference::Identity(id), - ) => id.certificate().unwrap().subject() == cert.subject(), - _ => false, - }) - ); - - // Clean up - cert.delete()?; - // NOTE(kcking): Deleting the certificate also deletes the identity since - // they are the same underlying object, so identity.delete() is not needed. - // identity.delete()?; - key.public_key().ok_or("no public key")?.delete()?; - key.delete()?; - Ok(()) - } -} diff --git a/native-pkcs11-piv/src/piv/key.rs b/native-pkcs11-piv/src/piv/key.rs index 3efecf2..9d9cbcc 100644 --- a/native-pkcs11-piv/src/piv/key.rs +++ b/native-pkcs11-piv/src/piv/key.rs @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fmt::Debug; - use core_foundation::base::ToVoid; use native_pkcs11_traits::{KeyAlgorithm, PrivateKey, PublicKey, SignatureAlgorithm}; use security_framework::{ - item::{ItemClass, KeyClass, Limit, Location, Reference}, - key::{GenerateKeyOptions, KeyType, SecKey}, + item::{ItemClass, KeyClass, Limit, Reference}, + key::SecKey, }; // TODO(bweeks,kcking): remove dependency on security-framework-sys crate. use security_framework_sys::item::{ @@ -27,6 +25,7 @@ use security_framework_sys::item::{ kSecAttrKeyTypeRSA, kSecAttrTokenID, }; +use std::fmt::Debug; use tracing::instrument; use crate::Result; @@ -67,7 +66,7 @@ fn sigalg_to_seckeyalg( return Err(crate::ErrorKind::UnsupportedSignatureAlgorithm( signature_algorithm.clone(), ) - .into()); + .into()); } match mask_generation_function { native_pkcs11_traits::DigestType::Sha1 => RSASignatureDigestPSSSHA1, @@ -248,30 +247,6 @@ impl PublicKey for YubikeyPivPublicKey { } } -#[instrument(skip(location))] -pub fn generate_key( - algorithm: Algorithm, - label: &str, - location: Option, -) -> Result { - let (ty, size) = match algorithm { - Algorithm::RSA => (KeyType::rsa(), 2048), - Algorithm::ECC => (KeyType::ec(), 256), - }; - - let opts = GenerateKeyOptions { - key_type: Some(ty), - size_in_bits: Some(size), - label: Some(label.into()), - token: Some(security_framework::key::Token::Software), - location, - access_control: None, - } - .to_dictionary(); - - Ok(SecKey::generate(opts).map_err(|e| e.to_string())?) -} - pub fn find_key(class: KeyClass, label: &str) -> Result { let results = crate::keychain::item_search_options()? .load_refs(true) @@ -342,224 +317,3 @@ pub fn find_all_keys(key_class: KeyClass) -> Result> { Ok(keys) } - -#[cfg(test)] -mod test { - use core_foundation::base::{TCFType, ToVoid}; - use native_pkcs11_traits::{random_label, Backend}; - use security_framework::item::{add_item, AddRef, ItemAddOptions, Limit}; - use security_framework_sys::item::{kSecAttrLabel, kSecValueRef}; - use serial_test::serial; - - use super::*; - use crate::{keychain, KeychainBackend}; - #[test] - #[serial] - fn key_label() -> crate::Result<()> { - let label = random_label(); - let key = generate_key(Algorithm::RSA, &label, Some(keychain::location()?))?; - - let mut found = false; - for res in crate::keychain::item_search_options()? - .key_class(KeyClass::private()) - .limit(Limit::Max(1)) - .load_attributes(true) - .load_refs(true) - .label(&label) - .search()? - { - found = true; - let (found_key, found_label) = match res { - security_framework::item::SearchResult::Ref(_) => panic!(), - security_framework::item::SearchResult::Dict(d) => { - let key = unsafe { - SecKey::wrap_under_get_rule(d.get(kSecValueRef.to_void()).cast_mut().cast()) - }; - let label = unsafe { - core_foundation::string::CFString::wrap_under_get_rule( - d.get(kSecAttrLabel.to_void()).cast_mut().cast(), - ) - }; - (key, label.to_string()) - } - security_framework::item::SearchResult::Data(_) => panic!(), - security_framework::item::SearchResult::Other => panic!(), - }; - - assert_eq!( - found_key.external_representation().unwrap().to_vec(), - key.external_representation().unwrap().to_vec() - ); - - assert_eq!(found_label, label); - } - key.public_key().unwrap().delete()?; - key.delete()?; - assert!(found); - Ok(()) - } - - #[test] - #[serial] - fn key_lifecycle() -> Result<()> { - for (key_alg, sig_alg) in [ - ( - Algorithm::ECC, - security_framework_sys::key::Algorithm::ECDSASignatureDigestX962, - ), - ( - Algorithm::RSA, - security_framework_sys::key::Algorithm::RSASignatureDigestPKCS1v15Raw, - ), - ] { - let label = &random_label(); - - let key = generate_key(key_alg, label, Some(keychain::location()?))?; - - let first_pubkey = key - .public_key() - .ok_or("no pubkey")? - .external_representation() - .ok_or("no external_representation")? - .to_vec(); - - std::mem::drop(key); - - let loaded_key = find_key(KeyClass::private(), label)?; - - let payload = vec![0u8; 32]; - let signature = loaded_key.create_signature(sig_alg, &payload)?; - - let loaded_pubkey = loaded_key.public_key().ok_or("no pubkey")?; - let sig_valid = loaded_pubkey.verify_signature(sig_alg, &payload, &signature)?; - assert!(sig_valid); - - assert_eq!( - loaded_pubkey.external_representation().unwrap().to_vec(), - first_pubkey - ); - - loaded_key.public_key().ok_or("no pubkey")?.delete()?; - loaded_key.delete()?; - } - - Ok(()) - } - - #[test] - #[ignore] - fn stress_test_keygen() { - let try_gen_key = || -> bool { - let label = random_label(); - match generate_key(Algorithm::RSA, &label, Some(keychain::location().unwrap())) { - Ok(key) => { - let _ = key.delete(); - true - } - Err(e) => { - eprintln!("{:?}", e); - false - } - } - }; - - let mut handles = vec![]; - for _ in 0..20 { - handles.push(std::thread::spawn(try_gen_key)); - } - assert!( - handles - .into_iter() - .map(|h| h.join().unwrap()) - // fold so we don't early exit other threads - .all(|b| b) - ); - } - - #[test] - #[ignore = "https://github.com/google/native-pkcs11/issues/302"] - fn keychain_pubkey_hash_find() -> Result<()> { - let key1 = generate_key(Algorithm::ECC, &random_label(), Some(keychain::location()?))?; - let key2 = generate_key(Algorithm::ECC, &random_label(), Some(keychain::location()?))?; - assert_ne!(key1.application_label(), key2.application_label()); - - for keyclass in [KeyClass::public(), KeyClass::private()] { - for key in [&key1, &key2] { - assert_eq!( - find_key2(keyclass, &key.application_label().unwrap())? - .unwrap() - .application_label() - .unwrap(), - key.application_label().unwrap() - ); - } - } - - for key in [&key1, &key2] { - key.public_key().as_ref().map(SecKey::delete); - let _ = key.delete(); - } - - Ok(()) - } - - #[test] - #[ignore = "demonstrate bug"] - fn unpersisted_public_key() -> Result<()> { - // NOTE(kcking): - // 1) Manually-imported keys are super scuffed. - // Manually imported key can be searched by label (if imported with - // that label), but cannot be searched by application_label (aka public - // key hash). Perhaps we are supposed to set this value at import time. - // - // 2) Manually-imported private keys do not return a corresponding - // public key from SecKeyCopyPublicKey (`.public_key()` in rust). - - let label = random_label(); - let key1 = SecKey::generate( - GenerateKeyOptions::default() - .set_key_type(KeyType::ec()) - .set_label(&label) - .to_dictionary(), - )?; - - let pubkey_hash = key1.public_key().unwrap().application_label().unwrap(); - - add_item( - ItemAddOptions::new(security_framework::item::ItemAddValue::Ref(AddRef::Key( - key1, - ))) - .set_label(&label) - .to_dictionary(), - )?; - - // NOTE(kcking): this fails to find the generated key, most likely - // because application_label is not automatically populated by - // SecurityFramework when importing a SecKey - // - // let found_key = - // KeychainBackend::find_private_key(native_pkcs11_traits::KeySearchOptions::PublicKeyHash( - // pubkey_hash - // .as_slice() - // .try_into() - // .map_err(|_| "into array")?, - // )) - // .map_err(|e| { - // dbg!(e); - // "find" - // })? - // .unwrap(); - - let found_key = KeychainBackend - .find_private_key(native_pkcs11_traits::KeySearchOptions::Label(label)) - .map_err(|e| { - dbg!(e); - "find" - })? - .unwrap(); - - assert_eq!(pubkey_hash, found_key.public_key_hash()); - - Ok(()) - } -}