in key/aziot-keys/src/key.rs [559:683]
fn create_inner(
locations: &[crate::implementation::Location],
create_method: CreateMethod<'_>,
usage: crate::AZIOT_KEYS_KEY_USAGE,
) -> Result<(), crate::AZIOT_KEYS_RC> {
for location in locations {
match location {
crate::implementation::Location::Filesystem(path) => {
let result = match create_method {
CreateMethod::Generate => {
// Filesystem uses AES-256-GCM for encryption keys and HMAC-SHA256 for hash keys,
// so it uses 256-bit == 32-byte keys for both.
let mut bytes = vec![0_u8; 32];
openssl::rand::rand_bytes(&mut bytes)?;
std::fs::write(path, bytes)
}
CreateMethod::Import(bytes) => std::fs::write(path, bytes),
};
let () = result.map_err(crate::implementation::err_external)?;
return Ok(());
}
crate::implementation::Location::Pkcs11 { lib_path, uri } => {
let usage = match usage {
#[allow(unreachable_patterns)] // DERIVE and SIGN are the same constant
crate::AZIOT_KEYS_KEY_USAGE_DERIVE | crate::AZIOT_KEYS_KEY_USAGE_SIGN => {
pkcs11::KeyUsage::Hmac
}
crate::AZIOT_KEYS_KEY_USAGE_ENCRYPT => pkcs11::KeyUsage::Aes,
_ => {
return Err(crate::implementation::err_invalid_parameter(
"usage",
"unrecognized value",
))
}
};
let pkcs11_context = pkcs11::Context::load(lib_path.clone())
.map_err(crate::implementation::err_external)?;
let pkcs11_slot = pkcs11_context
.find_slot(&uri.slot_identifier)
.map_err(crate::implementation::err_external)?;
let pkcs11_session = pkcs11_context
.open_session(pkcs11_slot, uri.pin.clone())
.map_err(crate::implementation::err_external)?;
let pkcs11_object = match create_method {
CreateMethod::Generate => {
let result = pkcs11_session
.clone()
.generate_key(uri.object_label.as_deref(), usage);
#[allow(clippy::unnested_or_patterns)]
match result {
Ok(pkcs11_key) => pkcs11_key,
Err(pkcs11::GenerateKeyError::GenerateKeyFailed(
pkcs11_sys::CKR_FUNCTION_NOT_SUPPORTED,
)) |
// Some PKCS#11 implementations like Cryptoauthlib don't support `C_GenerateKey(CKM_GENERIC_SECRET_KEY_GEN)`
Err(pkcs11::GenerateKeyError::GenerateKeyFailed(
pkcs11_sys::CKR_MECHANISM_INVALID,
)) => continue,
Err(err) => return Err(crate::implementation::err_external(err)),
}
}
CreateMethod::Import(bytes) => {
// TODO: Verify if CAL actually smashes the stack for keys that are too large,
// and if not, if it returns a better error than CKR_GENERAL_ERROR
let result = pkcs11_session.clone().import_key(
bytes,
uri.object_label.as_deref(),
usage,
);
match result {
Ok(pkcs11_key) => pkcs11_key,
// No better error from some PKCS#11 implementations like Cryptoauthlib than CKR_GENERAL_ERROR
Err(pkcs11::ImportKeyError::CreateObjectFailed(_)) => continue,
Err(err) => return Err(crate::implementation::err_external(err)),
}
}
};
if let pkcs11::KeyUsage::Aes = usage {
// At this point we've successfully created an AES key but we don't know if the token supports AES-GCM specifically or not.
// So we do a dummy encryption.
let iv: &[u8; 12] = b"123456789012";
let aad = b"someaad";
let plaintext = b"someplaintext";
// We can use the block size of AES-256-GCM from openssl even though the token didn't necessarily use AES-256-GCM,
// because all AES ciphers have the same block size by definition.
let cipher = openssl::symm::Cipher::aes_256_gcm();
let mut ciphertext = vec![0_u8; plaintext.len() + cipher.block_size() + 16];
if pkcs11_object
.encrypt(iv, aad, plaintext, &mut ciphertext)
.is_ok()
{
return Ok(());
}
// Delete the object we just created...
if let Some(object_label) = &uri.object_label {
let _ = pkcs11_session.clone().delete_key(object_label);
}
// ... and continue to the next location.
} else {
return Ok(());
}
}
}
}
Err(crate::implementation::err_external(
"no valid location for symmetric key",
))
}