Merge "Align KeyMint AIDL with usage"
diff --git a/keystore2/src/apc.rs b/keystore2/src/apc.rs
index 46b71dd..848b770 100644
--- a/keystore2/src/apc.rs
+++ b/keystore2/src/apc.rs
@@ -28,10 +28,10 @@
ResponseCode::ResponseCode,
};
use android_security_apc::binder::{
- ExceptionCode, Interface, Result as BinderResult, SpIBinder, Status as BinderStatus, Strong,
+ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, SpIBinder,
+ Status as BinderStatus, Strong, ThreadState,
};
use anyhow::{Context, Result};
-use binder::{IBinderInternal, ThreadState};
use keystore2_apc_compat::ApcHal;
use keystore2_selinux as selinux;
use std::time::{Duration, Instant};
@@ -203,11 +203,10 @@
pub fn new_native_binder(
confirmation_token_sender: Sender<Vec<u8>>,
) -> Result<Strong<dyn IProtectedConfirmation>> {
- let result = BnProtectedConfirmation::new_binder(Self {
- state: Arc::new(Mutex::new(ApcState::new(confirmation_token_sender))),
- });
- result.as_binder().set_requesting_sid(true);
- Ok(result)
+ Ok(BnProtectedConfirmation::new_binder(
+ Self { state: Arc::new(Mutex::new(ApcState::new(confirmation_token_sender))) },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ ))
}
fn result(
diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs
index 06b5598..ec1edff 100644
--- a/keystore2/src/authorization.rs
+++ b/keystore2/src/authorization.rs
@@ -22,7 +22,7 @@
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
HardwareAuthToken::HardwareAuthToken,
};
-use android_security_authorization::binder::{ExceptionCode, Interface, Result as BinderResult,
+use android_security_authorization::binder::{BinderFeatures,ExceptionCode, Interface, Result as BinderResult,
Strong, Status as BinderStatus};
use android_security_authorization::aidl::android::security::authorization::{
IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization,
@@ -32,7 +32,6 @@
use android_system_keystore2::aidl::android::system::keystore2::{
ResponseCode::ResponseCode as KsResponseCode };
use anyhow::{Context, Result};
-use binder::IBinderInternal;
use keystore2_crypto::Password;
use keystore2_selinux as selinux;
@@ -112,13 +111,14 @@
impl AuthorizationManager {
/// Create a new instance of Keystore Authorization service.
pub fn new_native_binder() -> Result<Strong<dyn IKeystoreAuthorization>> {
- let result = BnKeystoreAuthorization::new_binder(Self);
- result.as_binder().set_requesting_sid(true);
- Ok(result)
+ Ok(BnKeystoreAuthorization::new_binder(
+ Self,
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ ))
}
fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
- //check keystore permission
+ // Check keystore permission.
check_keystore_permission(KeystorePerm::add_auth()).context("In add_auth_token.")?;
ENFORCEMENTS.add_auth_token(auth_token.clone())?;
@@ -133,8 +133,8 @@
) -> Result<()> {
match (lock_screen_event, password) {
(LockScreenEvent::UNLOCK, Some(password)) => {
- //This corresponds to the unlock() method in legacy keystore API.
- //check permission
+ // This corresponds to the unlock() method in legacy keystore API.
+ // check permission
check_keystore_permission(KeystorePerm::unlock())
.context("In on_lock_screen_event: Unlock with password.")?;
ENFORCEMENTS.set_device_locked(user_id, false);
@@ -201,7 +201,7 @@
check_keystore_permission(KeystorePerm::get_auth_token())
.context("In get_auth_tokens_for_credstore.")?;
- // if the challenge is zero, return error
+ // If the challenge is zero, return error
if challenge == 0 {
return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
.context("In get_auth_tokens_for_credstore. Challenge can not be zero.");
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 7993c88..378b72f 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -61,47 +61,54 @@
state: AuthRequestState,
/// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
/// AuthRequestState::TimeStampedOpAuth.
- hat: Option<HardwareAuthToken>,
+ hat: Mutex<Option<HardwareAuthToken>>,
}
+unsafe impl Sync for AuthRequest {}
+
impl AuthRequest {
- fn op_auth() -> Arc<Mutex<Self>> {
- Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
+ fn op_auth() -> Arc<Self> {
+ Arc::new(Self { state: AuthRequestState::OpAuth, hat: Mutex::new(None) })
}
- fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
- Arc::new(Mutex::new(Self {
+ fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Self> {
+ Arc::new(Self {
state: AuthRequestState::TimeStampedOpAuth(receiver),
- hat: None,
- }))
+ hat: Mutex::new(None),
+ })
}
fn timestamp(
hat: HardwareAuthToken,
receiver: Receiver<Result<TimeStampToken, Error>>,
- ) -> Arc<Mutex<Self>> {
- Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
+ ) -> Arc<Self> {
+ Arc::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Mutex::new(Some(hat)) })
}
- fn add_auth_token(&mut self, hat: HardwareAuthToken) {
- self.hat = Some(hat)
+ fn add_auth_token(&self, hat: HardwareAuthToken) {
+ *self.hat.lock().unwrap() = Some(hat)
}
- fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
- match (&self.state, self.hat.is_some()) {
- (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
- (AuthRequestState::TimeStampedOpAuth(recv), true)
- | (AuthRequestState::TimeStamp(recv), true) => {
+ fn get_auth_tokens(&self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
+ let hat = self
+ .hat
+ .lock()
+ .unwrap()
+ .take()
+ .ok_or(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
+ .context("In get_auth_tokens: No operation auth token received.")?;
+
+ let tst = match &self.state {
+ AuthRequestState::TimeStampedOpAuth(recv) | AuthRequestState::TimeStamp(recv) => {
let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
- let tst = result.context(concat!(
+ Some(result.context(concat!(
"In get_auth_tokens: Worker responded with error ",
"from generating timestamp token."
- ))?;
- Ok((self.hat.take().unwrap(), Some(tst)))
+ ))?)
}
- (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
- .context("In get_auth_tokens: No operation auth token received."),
- }
+ AuthRequestState::OpAuth => None,
+ };
+ Ok((hat, tst))
}
}
@@ -127,7 +134,7 @@
/// We block on timestamp tokens, because we can always make progress on these requests.
/// The per-op auth tokens might never come, which means we fail if the client calls
/// update or finish before we got a per-op auth token.
- Waiting(Arc<Mutex<AuthRequest>>),
+ Waiting(Arc<AuthRequest>),
/// In this state we have gotten all of the required tokens, we just cache them to
/// be used when the operation progresses.
Token(HardwareAuthToken, Option<TimeStampToken>),
@@ -169,9 +176,15 @@
const CLEANUP_PERIOD: u8 = 25;
pub fn add_auth_token(&self, hat: HardwareAuthToken) {
- let mut map = self.map_and_cleanup_counter.lock().unwrap();
- let (ref mut map, _) = *map;
- if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
+ let recv = {
+ // Limit the scope of the mutex guard, so that it is not held while the auth token is
+ // added.
+ let mut map = self.map_and_cleanup_counter.lock().unwrap();
+ let (ref mut map, _) = *map;
+ map.remove_entry(&hat.challenge)
+ };
+
+ if let Some((_, recv)) = recv {
recv.add_auth_token(hat);
}
}
@@ -191,7 +204,7 @@
}
#[derive(Debug)]
-struct TokenReceiver(Weak<Mutex<AuthRequest>>);
+struct TokenReceiver(Weak<AuthRequest>);
impl TokenReceiver {
fn is_obsolete(&self) -> bool {
@@ -200,8 +213,7 @@
fn add_auth_token(&self, hat: HardwareAuthToken) {
if let Some(state_arc) = self.0.upgrade() {
- let mut state = state_arc.lock().unwrap();
- state.add_auth_token(hat);
+ state_arc.add_auth_token(hat);
}
}
}
@@ -326,8 +338,7 @@
/// tokens into the DeferredAuthState::Token state for future use.
fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
- let mut state = auth_request.lock().unwrap();
- Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
+ Some(auth_request.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
} else {
None
};
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_migrator.rs
index e5bcae4..5e0d573 100644
--- a/keystore2/src/legacy_migrator.rs
+++ b/keystore2/src/legacy_migrator.rs
@@ -420,7 +420,7 @@
.context("In list_uid: Trying to list legacy entries.")
}
- /// This is a key migration request that can run in the migrator thread. This should
+ /// This is a key migration request that must run in the migrator thread. This must
/// be passed to do_serialized.
fn check_and_migrate(&mut self, uid: u32, mut key: KeyDescriptor) -> Result<()> {
let alias = key.alias.clone().ok_or_else(|| {
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 1691f9d..9e7576e 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -29,13 +29,14 @@
IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
UserState::UserState as AidlUserState,
};
-use android_security_maintenance::binder::{Interface, Result as BinderResult};
+use android_security_maintenance::binder::{
+ BinderFeatures, Interface, Result as BinderResult, Strong, ThreadState,
+};
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, KeyDescriptor::KeyDescriptor,
};
use anyhow::{Context, Result};
-use binder::{IBinderInternal, Strong, ThreadState};
use keystore2_crypto::Password;
/// This struct is defined to implement the aforementioned AIDL interface.
@@ -45,9 +46,10 @@
impl Maintenance {
/// Create a new instance of Keystore User Manager service.
pub fn new_native_binder() -> Result<Strong<dyn IKeystoreMaintenance>> {
- let result = BnKeystoreMaintenance::new_binder(Self);
- result.as_binder().set_requesting_sid(true);
- Ok(result)
+ Ok(BnKeystoreMaintenance::new_binder(
+ Self,
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ ))
}
fn on_user_password_changed(user_id: i32, password: Option<Password>) -> Result<()> {
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index c2539a7..0b5c77a 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -133,11 +133,11 @@
IKeyMintOperation::IKeyMintOperation, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
SecurityLevel::SecurityLevel,
};
+use android_hardware_security_keymint::binder::BinderFeatures;
use android_system_keystore2::aidl::android::system::keystore2::{
IKeystoreOperation::BnKeystoreOperation, IKeystoreOperation::IKeystoreOperation,
};
use anyhow::{anyhow, Context, Result};
-use binder::IBinderInternal;
use std::{
collections::HashMap,
sync::{Arc, Mutex, MutexGuard, Weak},
@@ -783,16 +783,16 @@
impl KeystoreOperation {
/// Creates a new operation instance wrapped in a
- /// BnKeystoreOperation proxy object. It also
- /// calls `IBinderInternal::set_requesting_sid` on the new interface, because
+ /// BnKeystoreOperation proxy object. It also enables
+ /// `BinderFeatures::set_requesting_sid` on the new interface, because
/// we need it for checking Keystore permissions.
pub fn new_native_binder(
operation: Arc<Operation>,
) -> binder::public_api::Strong<dyn IKeystoreOperation> {
- let result =
- BnKeystoreOperation::new_binder(Self { operation: Mutex::new(Some(operation)) });
- result.as_binder().set_requesting_sid(true);
- result
+ BnKeystoreOperation::new_binder(
+ Self { operation: Mutex::new(Some(operation)) },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ )
}
/// Grabs the outer operation mutex and calls `f` on the locked operation.
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index f99805d..f8ee369 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -34,7 +34,7 @@
AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
IRemoteProvisioning::IRemoteProvisioning,
};
-use android_security_remoteprovisioning::binder::Strong;
+use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, KeyDescriptor::KeyDescriptor,
};
@@ -233,7 +233,7 @@
if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
}
- Ok(BnRemoteProvisioning::new_binder(result))
+ Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
}
/// Populates the AttestationPoolStatus parcelable with information about how many
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index e4af009..fdf9d1b 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -22,10 +22,11 @@
KeyMintHardwareInfo::KeyMintHardwareInfo, KeyParameter::KeyParameter,
KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel, Tag::Tag,
};
+use android_hardware_security_keymint::binder::{BinderFeatures, Strong, ThreadState};
use android_system_keystore2::aidl::android::system::keystore2::{
AuthenticatorSpec::AuthenticatorSpec, CreateOperationResponse::CreateOperationResponse,
- Domain::Domain, IKeystoreOperation::IKeystoreOperation,
- IKeystoreSecurityLevel::BnKeystoreSecurityLevel,
+ Domain::Domain, EphemeralStorageKeyResponse::EphemeralStorageKeyResponse,
+ IKeystoreOperation::IKeystoreOperation, IKeystoreSecurityLevel::BnKeystoreSecurityLevel,
IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
KeyMetadata::KeyMetadata, KeyParameters::KeyParameters,
};
@@ -57,7 +58,6 @@
utils::key_characteristics_to_internal,
};
use anyhow::{anyhow, Context, Result};
-use binder::{IBinderInternal, Strong, ThreadState};
/// Implementation of the IKeystoreSecurityLevel Interface.
pub struct KeystoreSecurityLevel {
@@ -79,8 +79,8 @@
impl KeystoreSecurityLevel {
/// Creates a new security level instance wrapped in a
- /// BnKeystoreSecurityLevel proxy object. It also
- /// calls `IBinderInternal::set_requesting_sid` on the new interface, because
+ /// BnKeystoreSecurityLevel proxy object. It also enables
+ /// `BinderFeatures::set_requesting_sid` on the new interface, because
/// we need it for checking keystore permissions.
pub fn new_native_binder(
security_level: SecurityLevel,
@@ -88,16 +88,18 @@
) -> Result<(Strong<dyn IKeystoreSecurityLevel>, Uuid)> {
let (dev, hw_info, km_uuid) = get_keymint_device(&security_level)
.context("In KeystoreSecurityLevel::new_native_binder.")?;
- let result = BnKeystoreSecurityLevel::new_binder(Self {
- security_level,
- keymint: dev,
- hw_info,
- km_uuid,
- operation_db: OperationDb::new(),
- rem_prov_state: RemProvState::new(security_level, km_uuid),
- id_rotation_state,
- });
- result.as_binder().set_requesting_sid(true);
+ let result = BnKeystoreSecurityLevel::new_binder(
+ Self {
+ security_level,
+ keymint: dev,
+ hw_info,
+ km_uuid,
+ operation_db: OperationDb::new(),
+ rem_prov_state: RemProvState::new(security_level, km_uuid),
+ id_rotation_state,
+ },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ );
Ok((result, km_uuid))
}
@@ -781,7 +783,10 @@
}
}
- fn convert_storage_key_to_ephemeral(&self, storage_key: &KeyDescriptor) -> Result<Vec<u8>> {
+ fn convert_storage_key_to_ephemeral(
+ &self,
+ storage_key: &KeyDescriptor,
+ ) -> Result<EphemeralStorageKeyResponse> {
if storage_key.domain != Domain::BLOB {
return Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT)).context(concat!(
"In IKeystoreSecurityLevel convert_storage_key_to_ephemeral: ",
@@ -804,8 +809,26 @@
"In IKeystoreSecurityLevel convert_storage_key_to_ephemeral: ",
"Getting keymint device interface"
))?;
- map_km_error(km_dev.convertStorageKeyToEphemeral(key_blob))
- .context("In keymint device convertStorageKeyToEphemeral")
+ match map_km_error(km_dev.convertStorageKeyToEphemeral(key_blob)) {
+ Ok(result) => {
+ Ok(EphemeralStorageKeyResponse { ephemeralKey: result, upgradedBlob: None })
+ }
+ Err(error::Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
+ let upgraded_blob = map_km_error(km_dev.upgradeKey(key_blob, &[]))
+ .context("In convert_storage_key_to_ephemeral: Failed to upgrade key blob.")?;
+ let ephemeral_key = map_km_error(km_dev.convertStorageKeyToEphemeral(key_blob))
+ .context(concat!(
+ "In convert_storage_key_to_ephemeral: ",
+ "Failed to retrieve ephemeral key (after upgrade)."
+ ))?;
+ Ok(EphemeralStorageKeyResponse {
+ ephemeralKey: ephemeral_key,
+ upgradedBlob: Some(upgraded_blob),
+ })
+ }
+ Err(e) => Err(e)
+ .context("In convert_storage_key_to_ephemeral: Failed to retrieve ephemeral key."),
+ }
}
fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
@@ -882,7 +905,7 @@
fn convertStorageKeyToEphemeral(
&self,
storage_key: &KeyDescriptor,
- ) -> binder::public_api::Result<Vec<u8>> {
+ ) -> binder::public_api::Result<EphemeralStorageKeyResponse> {
map_or_log_err(self.convert_storage_key_to_ephemeral(storage_key), Ok)
}
fn deleteKey(&self, key: &KeyDescriptor) -> binder::public_api::Result<()> {
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 1debe1b..8d3b66e 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -37,13 +37,13 @@
id_rotation::IdRotationState,
};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_hardware_security_keymint::binder::{BinderFeatures, Strong, ThreadState};
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
IKeystoreService::BnKeystoreService, IKeystoreService::IKeystoreService,
KeyDescriptor::KeyDescriptor, KeyEntryResponse::KeyEntryResponse, KeyMetadata::KeyMetadata,
};
use anyhow::{Context, Result};
-use binder::{IBinderInternal, Strong, ThreadState};
use error::Error;
use keystore2_selinux as selinux;
@@ -90,9 +90,10 @@
"In KeystoreService::new_native_binder: Trying to initialize the legacy migrator.",
)?;
- let result = BnKeystoreService::new_binder(result);
- result.as_binder().set_requesting_sid(true);
- Ok(result)
+ Ok(BnKeystoreService::new_binder(
+ result,
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ ))
}
fn uuid_to_sec_level(&self, uuid: &Uuid) -> SecurityLevel {
diff --git a/keystore2/vpnprofilestore/lib.rs b/keystore2/vpnprofilestore/lib.rs
index 521b668..d92e045 100644
--- a/keystore2/vpnprofilestore/lib.rs
+++ b/keystore2/vpnprofilestore/lib.rs
@@ -18,9 +18,11 @@
IVpnProfileStore::BnVpnProfileStore, IVpnProfileStore::IVpnProfileStore,
IVpnProfileStore::ERROR_PROFILE_NOT_FOUND, IVpnProfileStore::ERROR_SYSTEM_ERROR,
};
-use android_security_vpnprofilestore::binder::{Result as BinderResult, Status as BinderStatus};
+use android_security_vpnprofilestore::binder::{
+ BinderFeatures, ExceptionCode, Result as BinderResult, Status as BinderStatus, Strong,
+ ThreadState,
+};
use anyhow::{Context, Result};
-use binder::{ExceptionCode, Strong, ThreadState};
use keystore2::{async_task::AsyncTask, legacy_blob::LegacyBlobLoader};
use rusqlite::{
params, Connection, OptionalExtension, Transaction, TransactionBehavior, NO_PARAMS,
@@ -224,7 +226,7 @@
let result = Self { db_path, async_task: Default::default() };
result.init_shelf(path);
- BnVpnProfileStore::new_binder(result)
+ BnVpnProfileStore::new_binder(result, BinderFeatures::default())
}
fn open_db(&self) -> Result<DB> {
diff --git a/ondevice-signing/Keymaster.cpp b/ondevice-signing/Keymaster.cpp
index 6cfb565..f9bf9b2 100644
--- a/ondevice-signing/Keymaster.cpp
+++ b/ondevice-signing/Keymaster.cpp
@@ -45,7 +45,6 @@
using android::sp;
using android::base::Error;
using android::base::Result;
-using android::base::unique_fd;
using android::hardware::hidl_vec;
Keymaster::Keymaster() {}
diff --git a/ondevice-signing/KeystoreKey.cpp b/ondevice-signing/KeystoreKey.cpp
index 96e369a..4e59c58 100644
--- a/ondevice-signing/KeystoreKey.cpp
+++ b/ondevice-signing/KeystoreKey.cpp
@@ -51,8 +51,6 @@
using android::base::Error;
using android::base::Result;
-using android::base::unique_fd;
-
// Keystore boot level that the odsign key uses
static const int kOdsignBootLevel = 30;