feat: remove generate key, since PIV key genration should use ykman

This commit is contained in:
2024-07-06 19:17:08 +08:00
parent 33f33d2aa6
commit d8a2309b95
3 changed files with 7 additions and 318 deletions

View File

@@ -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<Location>,
) -> Result<SecKey> {
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<SecKey> {
let results = crate::keychain::item_search_options()?
.load_refs(true)
@@ -342,224 +317,3 @@ pub fn find_all_keys(key_class: KeyClass) -> Result<Vec<SecKey>> {
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(())
}
}