Merge "keystore: remove unused Keystore1 files" into main am: ed4f8be6be

Original change: https://android-review.googlesource.com/c/platform/system/security/+/2915233

Change-Id: I1a3be97659a324c170d5e559b5047f16867c31af
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Eric Biggers 2024-01-18 21:06:17 +00:00 committed by Automerger Merge Worker
commit 545463ccbb
29 changed files with 0 additions and 3826 deletions

View file

@ -1,40 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_EXPORTRESULT_H_
#define KEYSTORE_INCLUDE_KEYSTORE_EXPORTRESULT_H_
#include <binder/Parcelable.h>
#include "keystore_return_types.h"
namespace android {
namespace security {
namespace keymaster {
struct ExportResult : public ::android::Parcelable {
ExportResult();
~ExportResult();
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
::keystore::KeyStoreServiceReturnCode resultCode;
hardware::hidl_vec<uint8_t> exportData;
};
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_EXPORTRESULT_H_

View file

@ -1,49 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYCHARACTERISTICS_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYCHARACTERISTICS_H_
#include <binder/Parcelable.h>
#include "KeymasterArguments.h"
#include "keymaster_types.h"
namespace android {
namespace security {
namespace keymaster {
// Parcelable version of keystore::KeyCharacteristics
struct KeyCharacteristics : public ::android::Parcelable {
KeyCharacteristics(){};
explicit KeyCharacteristics(::keystore::KeyCharacteristics&& other) {
softwareEnforced = std::move(other.softwareEnforced);
hardwareEnforced = std::move(other.hardwareEnforced);
}
explicit KeyCharacteristics(const ::keystore::KeyCharacteristics& other) {
softwareEnforced = KeymasterArguments(other.softwareEnforced);
hardwareEnforced = KeymasterArguments(other.hardwareEnforced);
}
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
KeymasterArguments softwareEnforced;
KeymasterArguments hardwareEnforced;
};
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYCHARACTERISTICS_H_

View file

@ -1,48 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERARGUMENTS_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERARGUMENTS_H_
#include <binder/Parcelable.h>
#include <keystore/keymaster_types.h>
namespace android {
namespace security {
namespace keymaster {
// struct for serializing/deserializing a list of KeyParameters
struct KeymasterArguments : public Parcelable {
KeymasterArguments(){};
// NOLINTNEXTLINE(google-explicit-constructor)
KeymasterArguments(hardware::hidl_vec<::keystore::KeyParameter>&& other);
explicit KeymasterArguments(const hardware::hidl_vec<::keystore::KeyParameter>& other);
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
const inline hardware::hidl_vec<::keystore::KeyParameter>& getParameters() const {
return data_;
}
private:
hardware::hidl_vec<::keystore::KeyParameter> data_;
};
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERARGUMENTS_H_

View file

@ -1,40 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERBLOB_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERBLOB_H_
#include <binder/Parcelable.h>
namespace android {
namespace security {
namespace keymaster {
// Parcelable which wraps hardware::hidl_vec<uint8_t>
struct KeymasterBlob : public ::android::Parcelable {
KeymasterBlob(){};
explicit KeymasterBlob(hardware::hidl_vec<uint8_t> data) : data_(data) {}
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
const hardware::hidl_vec<uint8_t>& getData() const { return data_; }
private:
hardware::hidl_vec<uint8_t> data_;
};
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERBLOB_H_

View file

@ -1,43 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_
#include <binder/Parcelable.h>
#include <keystore/keymaster_types.h>
namespace android {
namespace security {
namespace keymaster {
// struct for serializing keymaster_cert_chain_t's
struct KeymasterCertificateChain : public ::android::Parcelable {
KeymasterCertificateChain(){};
explicit KeymasterCertificateChain(hardware::hidl_vec<hardware::hidl_vec<uint8_t>> other)
: chain(std::move(other)) {}
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
private:
// The structure is only used as output and doesn't have getter.
hardware::hidl_vec<hardware::hidl_vec<uint8_t>> chain;
};
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_

View file

@ -1,58 +0,0 @@
// Copyright 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_
#define KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <utils/String8.h>
#include "keystore_return_types.h"
namespace android {
namespace security {
namespace keystore {
// struct for holding response code and optionally an error message for keystore
// AIDL callbacks
struct KeystoreResponse : public ::android::Parcelable {
public:
KeystoreResponse() = default;
explicit KeystoreResponse(const int response_code, const String16& error_msg)
: response_code_(response_code), error_msg_(error_msg) {}
explicit KeystoreResponse(const int response_code)
: response_code_(response_code), error_msg_() {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeystoreResponse(const ::keystore::KeyStoreServiceReturnCode& rc)
: response_code_(rc.getErrorCode()), error_msg_() {}
KeystoreResponse(const KeystoreResponse& other) = default;
KeystoreResponse(KeystoreResponse&& other) = default;
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
int response_code() const { return response_code_; }
const std::optional<String16>& error_msg() const { return error_msg_; }
private:
int response_code_;
std::optional<String16> error_msg_;
};
} // namespace keystore
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_

View file

@ -1,48 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_INCLUDE_KEYSTORE_OPERATIONRESULT_H_
#define KEYSTORE_INCLUDE_KEYSTORE_OPERATIONRESULT_H_
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include "keymaster_types.h"
#include "keystore_return_types.h"
namespace android {
namespace security {
namespace keymaster {
struct OperationResult : public ::android::Parcelable {
OperationResult();
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
// Native code may need to use KeyStoreNativeReturnCode
::keystore::KeyStoreServiceReturnCode resultCode;
sp<IBinder> token;
uint64_t handle;
int inputConsumed;
::keystore::hidl_vec<uint8_t> data;
::keystore::hidl_vec<::keystore::KeyParameter> outParams;
};
OperationResult operationFailed(const ::keystore::KeyStoreServiceReturnCode& error);
} // namespace keymaster
} // namespace security
} // namespace android
#endif // KEYSTORE_INCLUDE_KEYSTORE_OPERATIONRESULT_H_

View file

@ -1,109 +0,0 @@
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SECURITY_KEYSTORE_INCLUDE_KEYSTORE_KEYMASTER_TYPES_H_
#define SECURITY_KEYSTORE_INCLUDE_KEYSTORE_KEYMASTER_TYPES_H_
#include <android/hardware/keymaster/3.0/types.h>
#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
#include <android/hardware/keymaster/4.1/types.h>
#include <keymasterV4_1/authorization_set.h>
#include <keymasterV4_1/keymaster_tags.h>
/**
* This header lifts the types from the current Keymaster version into the keystore namespace.
*/
namespace keystore {
// Changing this namespace alias will change the keymaster version.
namespace keymaster = ::android::hardware::keymaster::V4_1;
using android::hardware::hidl_vec;
using android::hardware::Return;
using keymaster::IKeymasterDevice;
using keymaster::SecurityLevel;
using keymaster::AuthorizationSet;
using keymaster::AuthorizationSetBuilder;
// It's more convenient to use the V4.0 error and tag types by default.
using ::android::hardware::keymaster::V4_0::ErrorCode;
using ::android::hardware::keymaster::V4_0::Tag;
using V4_1_ErrorCode = ::android::hardware::keymaster::V4_1::ErrorCode;
using V4_1_Tag = ::android::hardware::keymaster::V4_1::Tag;
using keymaster::Algorithm;
using keymaster::BlockMode;
using keymaster::Digest;
using keymaster::EcCurve;
using keymaster::HardwareAuthenticatorType;
using keymaster::HardwareAuthToken;
using keymaster::HmacSharingParameters;
using keymaster::KeyCharacteristics;
using keymaster::KeyFormat;
using keymaster::KeyParameter;
using keymaster::KeyPurpose;
using keymaster::OperationHandle;
using keymaster::PaddingMode;
using keymaster::SecurityLevel;
using keymaster::TagType;
using keymaster::VerificationToken;
using keymaster::TAG_ACTIVE_DATETIME;
using keymaster::TAG_ALGORITHM;
using keymaster::TAG_ALLOW_WHILE_ON_BODY;
using keymaster::TAG_APPLICATION_DATA;
using keymaster::TAG_APPLICATION_ID;
using keymaster::TAG_ATTESTATION_APPLICATION_ID;
using keymaster::TAG_AUTH_TIMEOUT;
using keymaster::TAG_BLOB_USAGE_REQUIREMENTS;
using keymaster::TAG_BLOCK_MODE;
using keymaster::TAG_DIGEST;
using keymaster::TAG_EC_CURVE;
using keymaster::TAG_KEY_SIZE;
using keymaster::TAG_MAC_LENGTH;
using keymaster::TAG_MAX_USES_PER_BOOT;
using keymaster::TAG_MIN_MAC_LENGTH;
using keymaster::TAG_MIN_SECONDS_BETWEEN_OPS;
using keymaster::TAG_NO_AUTH_REQUIRED;
using keymaster::TAG_NONCE;
using keymaster::TAG_ORIGIN;
using keymaster::TAG_ORIGINATION_EXPIRE_DATETIME;
using keymaster::TAG_PADDING;
using keymaster::TAG_PURPOSE;
using keymaster::TAG_RESET_SINCE_ID_ROTATION;
using keymaster::TAG_RSA_PUBLIC_EXPONENT;
using keymaster::TAG_USAGE_EXPIRE_DATETIME;
using keymaster::TAG_USER_AUTH_TYPE;
using keymaster::TAG_USER_ID;
using keymaster::TAG_USER_SECURE_ID;
using keymaster::NullOr;
using Km3HardwareAuthToken = ::android::hardware::keymaster::V3_0::HardwareAuthToken;
using Km3HardwareAuthenticatorType =
::android::hardware::keymaster::V3_0::HardwareAuthenticatorType;
// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We
// need these old values to be able to support old keys that use them.
constexpr int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
constexpr int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
} // namespace keystore
#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_

View file

@ -1,85 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __KEYSTORE_H__
#define __KEYSTORE_H__
#include <stdint.h>
// note state values overlap with ResponseCode for the purposes of the state() API
enum State {
STATE_NO_ERROR = 1,
STATE_LOCKED = 2,
STATE_UNINITIALIZED = 3,
};
// must be in sync with KeyStore.java,
enum class ResponseCode : int32_t {
NO_ERROR = STATE_NO_ERROR, // 1
LOCKED = STATE_LOCKED, // 2
UNINITIALIZED = STATE_UNINITIALIZED, // 3
SYSTEM_ERROR = 4,
PROTOCOL_ERROR = 5,
PERMISSION_DENIED = 6,
KEY_NOT_FOUND = 7,
VALUE_CORRUPTED = 8,
UNDEFINED_ACTION = 9,
WRONG_PASSWORD_0 = 10,
WRONG_PASSWORD_1 = 11,
WRONG_PASSWORD_2 = 12,
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
SIGNATURE_INVALID = 14,
OP_AUTH_NEEDED = 15, // Auth is needed for this operation before it can be used.
KEY_ALREADY_EXISTS = 16,
KEY_PERMANENTLY_INVALIDATED = 17,
/**
* Following three response codes are for logging purposes only.
* The operations are logged at the end of the life cycle of an operation handle,
* along with the reason for the end of the operation handle. For the operations
* that fail in update and finish, the reason for failure is available with
* the above response codes.
* For the operations that are aborted in three different ways, the reason
* for aborting is not available. The following enum values define the
* three ways an operation can get aborted.
*/
ABORT_CALLED = 18,
PRUNED = 19,
BINDER_DIED = 20,
};
/*
* All the flags for import and insert calls.
*/
enum KeyStoreFlag : uint8_t {
KEYSTORE_FLAG_NONE = 0,
KEYSTORE_FLAG_ENCRYPTED = 1 << 0,
KEYSTORE_FLAG_FALLBACK = 1 << 1,
// KEYSTORE_FLAG_SUPER_ENCRYPTED is for blobs that are already encrypted by keymaster but have
// an additional layer of password-based encryption applied. The same encryption scheme is used
// as KEYSTORE_FLAG_ENCRYPTED, but it's safe to remove super-encryption when the password is
// cleared, rather than deleting blobs, and the error returned when attempting to use a
// super-encrypted blob while keystore is locked is different.
KEYSTORE_FLAG_SUPER_ENCRYPTED = 1 << 2,
// KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION is for blobs that are part of device encryption
// flow so it receives special treatment from keystore. For example this blob will not be super
// encrypted, and it will be stored separately under an unique UID instead. This flag should
// only be available to system uid.
KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3,
KEYSTORE_FLAG_STRONGBOX = 1 << 4,
};
#endif

View file

@ -1,191 +0,0 @@
// Copyright 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_KEYSTORE_CLIENT_H_
#define KEYSTORE_KEYSTORE_CLIENT_H_
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <android-base/macros.h>
#include "keymaster_types.h"
#include "keystore.h"
#include "keystore_return_types.h"
namespace keystore {
// An abstract class providing a convenient interface to keystore services. This
// interface is designed to:
// - hide details of the IPC mechanism (e.g. binder)
// - use std data types
// - encourage the use of keystore::AuthorizationSet[Builder]
// - be convenient for native services integrating with keystore
// - be safely mocked for unit testing (e.g. pure virtual methods)
//
// Example usage:
// KeystoreClient* keystore = new KeyStoreClientImpl();
// keystore->AddRandomNumberGeneratorEntropy("unpredictable");
//
// Notes on error codes:
// Keystore binder methods return a variety of values including ResponseCode
// values defined in keystore.h, keymaster_error_t values defined in
// keymaster_defs.h, or just 0 or -1 (both of which conflict with
// keymaster_error_t). The methods in this class converge on a single success
// indicator for convenience. KM_ERROR_OK was chosen over ::NO_ERROR for two
// reasons:
// 1) KM_ERROR_OK is 0, which is a common convention for success, is the gmock
// default, and allows error checks like 'if (error) {...'.
// 2) Although both pollute the global namespace, KM_ERROR_OK has a prefix per
// C convention and hopefully clients can use this interface without
// needing to include 'keystore.h' directly.
class KeystoreClient {
public:
KeystoreClient() = default;
virtual ~KeystoreClient() = default;
// Encrypts and authenticates |data| with minimal configuration for local
// decryption. If a key identified by |key_name| does not already exist it
// will be generated. On success returns true and populates |encrypted_data|.
// Note: implementations may generate more than one key but they will always
// have |key_name| as a prefix.
virtual bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
int32_t flags, std::string* encrypted_data) = 0;
// Decrypts and authenticates |encrypted_data| as output by
// EncryptWithAuthentication using the key(s) identified by |key_name|. On
// success returns true and populates |data|.
virtual bool decryptWithAuthentication(const std::string& key_name,
const std::string& encrypted_data,
std::string* data) = 0;
// Performs a Begin/Update/Finish sequence for an operation. The |purpose|,
// |key_name|, |input_parameters|, and |output_parameters| are as in
// BeginOperation. The |input_data| is as in UpdateOperation. The
// |signature_to_verify| and |output_data| are as in FinishOperation. On
// success returns true.
virtual bool oneShotOperation(KeyPurpose purpose, const std::string& key_name,
const keystore::AuthorizationSet& input_parameters,
const std::string& input_data,
const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters,
std::string* output_data) = 0;
// Adds |entropy| to the random number generator. Returns KM_ERROR_OK on
// success and a Keystore ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy,
int32_t flags) = 0;
// Generates a key according to the given |key_parameters| and stores it with
// the given |key_name|. The [hardware|software]_enforced_characteristics of
// the key are provided on success. Returns KM_ERROR_OK on success. Returns
// KM_ERROR_OK on success and a Keystore ResponseCode or keymaster_error_t on
// failure.
virtual KeyStoreNativeReturnCode
generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) = 0;
// Provides the [hardware|software]_enforced_characteristics of a key
// identified by |key_name|. Returns KM_ERROR_OK on success and a Keystore
// ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
getKeyCharacteristics(const std::string& key_name,
keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) = 0;
// Imports |key_data| in the given |key_format|, applies the given
// |key_parameters|, and stores it with the given |key_name|. The
// [hardware|software]_enforced_characteristics of the key are provided on
// success. Returns KM_ERROR_OK on success and a Keystore ResponseCode or
// keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
importKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
KeyFormat key_format, const std::string& key_data,
keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) = 0;
// Exports the public key identified by |key_name| to |export_data| using
// |export_format|. Returns KM_ERROR_OK on success and a Keystore ResponseCode
// or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode exportKey(KeyFormat export_format, const std::string& key_name,
std::string* export_data) = 0;
// Deletes the key identified by |key_name|. Returns KM_ERROR_OK on success
// and a Keystore ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode deleteKey(const std::string& key_name) = 0;
// Deletes all keys owned by the caller. Returns KM_ERROR_OK on success and a
// Keystore ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode deleteAllKeys() = 0;
// Begins a cryptographic operation (e.g. encrypt, sign) identified by
// |purpose| using the key identified by |key_name| and the given
// |input_parameters|. On success, any |output_parameters| and an operation
// |handle| are populated. Returns KM_ERROR_OK on success and a Keystore
// ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
beginOperation(KeyPurpose purpose, const std::string& key_name,
const keystore::AuthorizationSet& input_parameters,
keystore::AuthorizationSet* output_parameters, uint64_t* handle) = 0;
// Continues the operation associated with |handle| using the given
// |input_parameters| and |input_data|. On success, the
// |num_input_bytes_consumed| and any |output_parameters| are populated. Any
// |output_data| will be appended. Returns KM_ERROR_OK on success and a
// Keystore ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
updateOperation(uint64_t handle, const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, size_t* num_input_bytes_consumed,
keystore::AuthorizationSet* output_parameters, std::string* output_data) = 0;
// Finishes the operation associated with |handle| using the given
// |input_parameters| and, if necessary, a |signature_to_verify|. On success,
// any |output_parameters| are populated and |output_data| is appended.
// Returns KM_ERROR_OK on success and a Keystore ResponseCode or
// keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
finishOperation(uint64_t handle, const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters, std::string* output_data) = 0;
// Aborts the operation associated with |handle|. Returns KM_ERROR_OK on
// success and a Keystore ResponseCode or keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode abortOperation(uint64_t handle) = 0;
// Returns true if a key identified by |key_name| exists in the caller's
// key store. Returns false if an error occurs.
virtual bool doesKeyExist(const std::string& key_name) = 0;
// Provides a |key_name_list| containing all existing key names in the
// caller's key store starting with |prefix|. Returns true on success.
virtual bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) = 0;
// Provides a |key_name_list| containing all existing key names in the
// caller's key store starting with |prefix|. Returns true on success.
virtual bool listKeysOfUid(const std::string& prefix, int uid,
std::vector<std::string>* key_name_list) = 0;
virtual std::optional<std::vector<uint8_t>> getKey(const std::string& alias, int uid) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(KeystoreClient);
};
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_CLIENT_H_

View file

@ -1,127 +0,0 @@
// Copyright 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_KEYSTORE_CLIENT_IMPL_H_
#define KEYSTORE_KEYSTORE_CLIENT_IMPL_H_
#include "keystore_client.h"
#include <future>
#include <map>
#include <optional>
#include <string>
#include <vector>
#include <android/security/keystore/IKeystoreService.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <utils/StrongPointer.h>
namespace keystore {
class KeystoreClientImpl : public KeystoreClient {
public:
KeystoreClientImpl();
~KeystoreClientImpl() override = default;
// KeystoreClient methods.
bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
int32_t flags, std::string* encrypted_data) override;
bool decryptWithAuthentication(const std::string& key_name, const std::string& encrypted_data,
std::string* data) override;
bool oneShotOperation(KeyPurpose purpose, const std::string& key_name,
const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy,
int32_t flags) override;
KeyStoreNativeReturnCode
generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) override;
KeyStoreNativeReturnCode
getKeyCharacteristics(const std::string& key_name,
keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) override;
KeyStoreNativeReturnCode
importKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters,
KeyFormat key_format, const std::string& key_data,
keystore::AuthorizationSet* hardware_enforced_characteristics,
keystore::AuthorizationSet* software_enforced_characteristics) override;
KeyStoreNativeReturnCode exportKey(KeyFormat export_format, const std::string& key_name,
std::string* export_data) override;
KeyStoreNativeReturnCode deleteKey(const std::string& key_name) override;
KeyStoreNativeReturnCode deleteAllKeys() override;
KeyStoreNativeReturnCode beginOperation(KeyPurpose purpose, const std::string& key_name,
const keystore::AuthorizationSet& input_parameters,
keystore::AuthorizationSet* output_parameters,
uint64_t* handle) override;
KeyStoreNativeReturnCode updateOperation(uint64_t handle,
const keystore::AuthorizationSet& input_parameters,
const std::string& input_data,
size_t* num_input_bytes_consumed,
keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
KeyStoreNativeReturnCode finishOperation(uint64_t handle,
const keystore::AuthorizationSet& input_parameters,
const std::string& input_data,
const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
KeyStoreNativeReturnCode abortOperation(uint64_t handle) override;
bool doesKeyExist(const std::string& key_name) override;
bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) override;
bool listKeysOfUid(const std::string& prefix, int uid,
std::vector<std::string>* key_name_list) override;
std::optional<std::vector<uint8_t>> getKey(const std::string& alias, int uid) override;
private:
// Returns an available virtual operation handle.
uint64_t getNextVirtualHandle();
// Maps a keystore error code to a code where all success cases use
// KM_ERROR_OK (not keystore's NO_ERROR).
// int32_t mapKeystoreError(int32_t keystore_error);
// Creates an encryption key suitable for EncryptWithAuthentication or
// verifies attributes if the key already exists. Returns true on success.
bool createOrVerifyEncryptionKey(const std::string& key_name, int32_t flags);
// Creates an authentication key suitable for EncryptWithAuthentication or
// verifies attributes if the key already exists. Returns true on success.
bool createOrVerifyAuthenticationKey(const std::string& key_name, int32_t flags);
// Verifies attributes of an encryption key suitable for
// EncryptWithAuthentication. Returns true on success and populates |verified|
// with the result of the verification.
bool verifyEncryptionKeyAttributes(const std::string& key_name, bool* verified);
// Verifies attributes of an authentication key suitable for
// EncryptWithAuthentication. Returns true on success and populates |verified|
// with the result of the verification.
bool verifyAuthenticationKeyAttributes(const std::string& key_name, bool* verified);
android::sp<android::IServiceManager> service_manager_;
android::sp<android::IBinder> keystore_binder_;
android::sp<android::security::keystore::IKeystoreService> keystore_;
uint64_t next_virtual_handle_ = 1;
std::map<uint64_t, android::sp<android::IBinder>> active_operations_;
DISALLOW_COPY_AND_ASSIGN(KeystoreClientImpl);
};
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_CLIENT_IMPL_H_

View file

@ -1,88 +0,0 @@
// Copyright 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef KEYSTORE_KEYSTORE_CLIENT_MOCK_H_
#define KEYSTORE_KEYSTORE_CLIENT_MOCK_H_
#include "keystore/keystore_client.h"
#include "gmock/gmock.h"
using testing::_;
namespace keystore {
// A mock implementation of KeystoreClient. By default all methods do nothing
// and return KM_ERROR_OK (or false).
class KeystoreClientMock : public KeystoreClient {
public:
KeystoreClientMock() = default;
~KeystoreClientMock() = default;
MOCK_METHOD3(encryptWithAuthentication,
bool(const std::string& key_name, const std::string& data,
std::string* encrypted_data));
MOCK_METHOD3(decryptWithAuthentication,
bool(const std::string& key_name, const std::string& encrypted_data,
std::string* data));
MOCK_METHOD7(oneShotOperation,
bool(keymaster_purpose_t purpose, const std::string& key_name,
const keymaster::AuthorizationSet& input_parameters,
const std::string& input_data, const std::string& signature_to_verify,
keymaster::AuthorizationSet* output_parameters, std::string* output_data));
MOCK_METHOD1(addRandomNumberGeneratorEntropy, int32_t(const std::string& entropy));
MOCK_METHOD4(generateKey,
int32_t(const std::string& key_name,
const keymaster::AuthorizationSet& key_parameters,
keymaster::AuthorizationSet* hardware_enforced_characteristics,
keymaster::AuthorizationSet* software_enforced_characteristics));
MOCK_METHOD3(getKeyCharacteristics,
int32_t(const std::string& key_name,
keymaster::AuthorizationSet* hardware_enforced_characteristics,
keymaster::AuthorizationSet* software_enforced_characteristics));
MOCK_METHOD6(importKey,
int32_t(const std::string& key_name,
const keymaster::AuthorizationSet& key_parameters,
keymaster_key_format_t key_format, const std::string& key_data,
keymaster::AuthorizationSet* hardware_enforced_characteristics,
keymaster::AuthorizationSet* software_enforced_characteristics));
MOCK_METHOD3(exportKey, int32_t(keymaster_key_format_t export_format,
const std::string& key_name, std::string* export_data));
MOCK_METHOD1(deleteKey, int32_t(const std::string& key_name));
MOCK_METHOD0(deleteAllKeys, int32_t());
MOCK_METHOD5(beginOperation, int32_t(keymaster_purpose_t purpose, const std::string& key_name,
const keymaster::AuthorizationSet& input_parameters,
keymaster::AuthorizationSet* output_parameters,
keymaster_operation_handle_t* handle));
MOCK_METHOD6(updateOperation,
int32_t(keymaster_operation_handle_t handle,
const keymaster::AuthorizationSet& input_parameters,
const std::string& input_data, size_t* num_input_bytes_consumed,
keymaster::AuthorizationSet* output_parameters, std::string* output_data));
MOCK_METHOD5(finishOperation,
int32_t(keymaster_operation_handle_t handle,
const keymaster::AuthorizationSet& input_parameters,
const std::string& signature_to_verify,
keymaster::AuthorizationSet* output_parameters, std::string* output_data));
MOCK_METHOD1(abortOperation, int32_t(keymaster_operation_handle_t handle));
MOCK_METHOD1(doesKeyExist, bool(const std::string& key_name));
MOCK_METHOD2(listKeys,
bool(const std::string& prefix, std::vector<std::string>* key_name_list));
private:
DISALLOW_COPY_AND_ASSIGN(KeystoreClientMock);
};
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_CLIENT_MOCK_H_

View file

@ -1,114 +0,0 @@
/*
**
** Copyright 2018, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
#include <type_traits>
namespace keystore {
template <typename LockedType> class UnlockProxyLockHelper {
private:
std::function<void(LockedType*)> unlock_;
LockedType* value_;
public:
using lockedType = LockedType;
UnlockProxyLockHelper() : value_(nullptr) {}
UnlockProxyLockHelper(LockedType* value, std::function<void(LockedType*)>&& unlock)
: unlock_(std::move(unlock)), value_(value) {}
~UnlockProxyLockHelper() {
if (unlock_) unlock_(value_);
}
UnlockProxyLockHelper(UnlockProxyLockHelper&& rhs)
: unlock_(std::move(rhs.unlock_)), value_(rhs.value_) {
rhs.value_ = nullptr;
rhs.unlock_ = {};
}
UnlockProxyLockHelper& operator=(UnlockProxyLockHelper&& rhs) {
if (this != &rhs) {
UnlockProxyLockHelper dummy(std::move(*this));
unlock_ = std::move(rhs.unlock_);
value_ = std::move(rhs.value_);
rhs.value_ = nullptr;
rhs.unlock_ = {};
}
return *this;
}
UnlockProxyLockHelper(const UnlockProxyLockHelper& rhs) = delete;
UnlockProxyLockHelper& operator=(const UnlockProxyLockHelper& rhs) = delete;
template <typename T = LockedType>
std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
return value_;
}
const LockedType* value() const { return value_; }
};
template <typename LockedType, typename MutexType, template <typename> class GuardType>
class MutexProxyLockHelper {
private:
GuardType<MutexType> lock_;
LockedType* value_;
public:
using lockedType = LockedType;
MutexProxyLockHelper() : value_(nullptr) {}
MutexProxyLockHelper(LockedType* value, GuardType<MutexType>&& lock)
: lock_(std::move(lock)), value_(value) {}
template <typename T = LockedType>
std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
return value_;
}
const LockedType* value() const { return value_; }
};
template <typename Implementation> class ProxyLock {
private:
Implementation impl_;
public:
ProxyLock() : impl_() {}
// NOLINTNEXTLINE(google-explicit-constructor)
template <typename... Args> ProxyLock(Args&&... args) : impl_{std::forward<Args>(args)...} {}
explicit ProxyLock(Implementation&& impl) : impl_(std::move(impl)) {}
explicit operator bool() const { return impl_.value() != nullptr; }
template <typename T = typename Implementation::lockedType>
std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T*> operator->() {
return impl_.value();
}
template <typename T = typename Implementation::lockedType>
std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T&> operator*() {
return *impl_.value();
}
const std::remove_const_t<typename Implementation::lockedType>* operator->() const {
return impl_.value();
}
const std::remove_const_t<typename Implementation::lockedType>& operator*() const {
return *impl_.value();
}
};
} // namespace keystore
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_

View file

@ -1,150 +0,0 @@
/*
**
** Copyright 2016, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
#define KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
#include <ostream>
#include <sstream>
#include <string>
#include <android-base/logging.h>
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include <hardware/hw_auth_token.h>
#include <hidl/Status.h>
#include <keymasterV4_0/keymaster_utils.h>
#include <keystore/keymaster_types.h>
namespace keystore {
using android::hardware::keymaster::V4_0::support::blob2hidlVec;
using android::hardware::keymaster::V4_0::support::hidlVec2AuthToken;
using android::hardware::keymaster::V4_0::support::authToken2HidlVec;
inline static std::ostream& formatArgs(std::ostream& out) {
return out;
}
template <typename First, typename... Args>
inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) {
out << first;
return formatArgs(out, args...);
}
template <typename... Args> inline static std::string argsToString(Args&&... args) {
std::stringstream s;
formatArgs(s, args...);
return s.str();
}
template <typename KMDevice, typename... Msgs>
inline static ErrorCode ksHandleHidlError(KMDevice dev, const Return<ErrorCode>& error,
Msgs&&... msgs) {
if (!error.isOk()) {
LOG(ERROR) << "HIDL call failed with " << error.description().c_str() << " @ "
<< argsToString(msgs...);
return ErrorCode::UNKNOWN_ERROR;
}
auto ec = ErrorCode(error);
dev->logIfKeymasterVendorError(ec);
return ec;
}
template <typename KMDevice, typename... Msgs>
inline static ErrorCode ksHandleHidlError(KMDevice, const Return<void>& error, Msgs&&... msgs) {
if (!error.isOk()) {
ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
argsToString(msgs...).c_str());
return ErrorCode::UNKNOWN_ERROR;
}
return ErrorCode::OK;
}
#define KS_HANDLE_HIDL_ERROR(dev, rc) \
::keystore::ksHandleHidlError(dev, rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__)
template <typename T, typename OutIter>
inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
return std::copy(value_ptr, value_ptr + sizeof(value), dest);
}
constexpr size_t kHmacSize = 32;
inline static hidl_vec<uint8_t> authToken2HidlVec(const Km3HardwareAuthToken& token) {
static_assert(std::is_same<decltype(token.hmac),
::android::hardware::hidl_array<uint8_t, kHmacSize>>::value,
"This function assumes token HMAC is 32 bytes, but it might not be.");
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
sizeof(token.timestamp) + kHmacSize ==
sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
hidl_vec<uint8_t> result;
result.resize(sizeof(hw_auth_token_t));
auto pos = result.begin();
*pos++ = 0; // Version byte
pos = copy_bytes_to_iterator(token.challenge, pos);
pos = copy_bytes_to_iterator(token.userId, pos);
pos = copy_bytes_to_iterator(token.authenticatorId, pos);
pos = copy_bytes_to_iterator(token.authenticatorType, pos);
pos = copy_bytes_to_iterator(token.timestamp, pos);
pos = std::copy(token.hmac.data(), token.hmac.data() + token.hmac.size(), pos);
return result;
}
template <typename T, typename InIter>
inline static InIter copy_bytes_from_iterator(T* value, InIter src) {
uint8_t* value_ptr = reinterpret_cast<uint8_t*>(value);
std::copy(src, src + sizeof(T), value_ptr);
return src + sizeof(T);
}
inline static Km3HardwareAuthToken hidlVec2Km3AuthToken(const hidl_vec<uint8_t>& buffer) {
Km3HardwareAuthToken token;
static_assert(std::is_same<decltype(token.hmac),
::android::hardware::hidl_array<uint8_t, kHmacSize>>::value,
"This function assumes token HMAC is 32 bytes, but it might not be.");
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
sizeof(token.timestamp) + kHmacSize ==
sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
if (buffer.size() != sizeof(hw_auth_token_t)) return {};
auto pos = buffer.begin();
++pos; // skip first byte
pos = copy_bytes_from_iterator(&token.challenge, pos);
pos = copy_bytes_from_iterator(&token.userId, pos);
pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
pos = copy_bytes_from_iterator(&token.timestamp, pos);
pos = std::copy(pos, pos + token.hmac.size(), &token.hmac[0]);
return token;
}
inline std::string hidlVec2String(const hidl_vec<uint8_t>& value) {
return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
}
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_

View file

@ -1,72 +0,0 @@
/*
**
** Copyright 2018, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_
#include <android/security/keystore/BnKeystoreCertificateChainCallback.h>
#include <android/security/keystore/BnKeystoreExportKeyCallback.h>
#include <android/security/keystore/BnKeystoreKeyCharacteristicsCallback.h>
#include <android/security/keystore/BnKeystoreOperationResultCallback.h>
#include <android/security/keystore/BnKeystoreResponseCallback.h>
#include <future>
namespace keystore {
template <typename BnInterface, typename Result>
class CallbackPromise : public BnInterface, public std::promise<Result> {
public:
::android::binder::Status onFinished(const Result& result) override {
this->set_value(result);
return ::android::binder::Status::ok();
}
};
template <typename BnInterface, typename... Results>
class CallbackPromise<BnInterface, std::tuple<Results...>>
: public BnInterface, public std::promise<std::tuple<Results...>> {
public:
::android::binder::Status onFinished(const Results&... results) override {
this->set_value({results...});
return ::android::binder::Status::ok();
}
};
using OperationResultPromise =
CallbackPromise<::android::security::keystore::BnKeystoreOperationResultCallback,
::android::security::keymaster::OperationResult>;
using KeystoreResponsePromise =
CallbackPromise<::android::security::keystore::BnKeystoreResponseCallback,
::android::security::keystore::KeystoreResponse>;
using KeyCharacteristicsPromise =
CallbackPromise<::android::security::keystore::BnKeystoreKeyCharacteristicsCallback,
std::tuple<::android::security::keystore::KeystoreResponse,
::android::security::keymaster::KeyCharacteristics>>;
using KeystoreExportPromise =
CallbackPromise<::android::security::keystore::BnKeystoreExportKeyCallback,
::android::security::keymaster::ExportResult>;
using KeyCertChainPromise =
CallbackPromise<::android::security::keystore::BnKeystoreCertificateChainCallback,
std::tuple<::android::security::keystore::KeystoreResponse,
::android::security::keymaster::KeymasterCertificateChain>>;
} // namespace keystore
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_

View file

@ -1,193 +0,0 @@
/*
**
** Copyright 2016, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_
#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_
#include "keymaster_types.h"
#include "keystore.h"
namespace keystore {
class KeyStoreServiceReturnCode;
class KeyStoreNativeReturnCode;
/**
* The keystore service return code is a bit tricky. It can return error codes from two name spaces:
* ErrorCode, which has negative error codes and use 0 for ERROR_OK;
* ResponseCode, which has positive error codes and uses 1 for NO_ERROR.
* This class can be initialized by both. And when accessed through the operator int32_t () it
* always returns ResponseCode::NO_ERROR (1) on success, even if it was initialized with
* ErrorCode::OK (0), because this is what (java) clients expect.
*
* !!! Do not confuse this with KeyStoreNativeReturnCode which always converts to 0 on success. !!!
*/
class KeyStoreServiceReturnCode {
public:
KeyStoreServiceReturnCode() : errorCode_(0) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
KeyStoreServiceReturnCode(const KeyStoreServiceReturnCode& errorCode)
: errorCode_(errorCode.errorCode_) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const KeyStoreNativeReturnCode& errorCode);
explicit inline KeyStoreServiceReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {}
inline KeyStoreServiceReturnCode& operator=(const ErrorCode& errorCode) {
errorCode_ = int32_t(errorCode);
return *this;
}
inline KeyStoreServiceReturnCode& operator=(const ResponseCode& errorCode) {
errorCode_ = int32_t(errorCode);
return *this;
}
inline KeyStoreServiceReturnCode& operator=(const KeyStoreServiceReturnCode& errorCode) {
errorCode_ = errorCode.errorCode_;
return *this;
}
inline bool isOk() const {
return errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) ||
errorCode_ == static_cast<int32_t>(ErrorCode::OK);
}
inline int32_t getErrorCode() const {
if (!errorCode_) return static_cast<int32_t>(ResponseCode::NO_ERROR /* 1 */);
return errorCode_;
}
inline bool operator==(const ResponseCode& rhs) const {
return (rhs == ResponseCode::NO_ERROR &&
errorCode_ == static_cast<int32_t>(ErrorCode::OK)) ||
errorCode_ == int32_t(rhs);
}
inline bool operator==(const ErrorCode& rhs) const {
return (rhs == ErrorCode::OK &&
errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR)) ||
errorCode_ == int32_t(rhs);
}
inline bool operator!=(const ResponseCode& rhs) const { return !(*this == rhs); }
inline bool operator!=(const ErrorCode& rhs) const { return !(*this == rhs); }
private:
int32_t errorCode_;
};
inline bool operator==(const ResponseCode& lhs, const KeyStoreServiceReturnCode& rhs) {
return rhs == lhs;
}
inline bool operator==(const ErrorCode& lhs, const KeyStoreServiceReturnCode& rhs) {
return rhs == lhs;
}
inline bool operator!=(const ResponseCode& lhs, const KeyStoreServiceReturnCode& rhs) {
return rhs != lhs;
}
inline bool operator!=(const ErrorCode& lhs, const KeyStoreServiceReturnCode& rhs) {
return rhs != lhs;
}
inline std::ostream& operator<<(std::ostream& out, const KeyStoreServiceReturnCode& error) {
return out << error.getErrorCode();
}
/**
* The keystore native return code is a bit tricky. It can return error codes from two name spaces:
* ErrorCode, which has negative error codes and use 0 for ERROR_OK;
* ResponseCode, which has positive error codes and uses 1 for NO_ERROR.
* This class can be initialized by both. And when accessed through the operator int32_t () it
* always returns ErrorCode::OK (0) on success, even if it was initialized with
* ResponseCode::NO_ERROR (1), because this is what (native) clients expect.
*
* !!! Do not this confuse with KeyStoreServiceReturnCode which always converts to 1 on success. !!!
*/
class KeyStoreNativeReturnCode {
public:
KeyStoreNativeReturnCode() : errorCode_(0) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
KeyStoreNativeReturnCode(const KeyStoreNativeReturnCode& errorCode)
: errorCode_(errorCode.errorCode_) {}
explicit inline KeyStoreNativeReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {}
// NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const KeyStoreServiceReturnCode& errorcode);
inline KeyStoreNativeReturnCode& operator=(const ErrorCode& errorCode) {
errorCode_ = int32_t(errorCode);
return *this;
}
inline KeyStoreNativeReturnCode& operator=(const ResponseCode& errorCode) {
errorCode_ = int32_t(errorCode);
return *this;
}
inline KeyStoreNativeReturnCode& operator=(const KeyStoreNativeReturnCode& errorCode) {
errorCode_ = errorCode.errorCode_;
return *this;
}
inline bool isOk() const {
return errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) ||
errorCode_ == static_cast<int32_t>(ErrorCode::OK);
}
inline int32_t getErrorCode() const {
if (errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) /* 1 */) {
return static_cast<int32_t>(ErrorCode::OK) /* 0 */;
}
return errorCode_;
}
inline bool operator==(const ResponseCode& rhs) const {
return (rhs == ResponseCode::NO_ERROR &&
errorCode_ == static_cast<int32_t>(ErrorCode::OK)) ||
errorCode_ == int32_t(rhs);
}
inline bool operator==(const ErrorCode& rhs) const {
return (rhs == ErrorCode::OK &&
errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR)) ||
errorCode_ == int32_t(rhs);
}
inline bool operator!=(const ResponseCode& rhs) const { return !(*this == rhs); }
inline bool operator!=(const ErrorCode& rhs) const { return !(*this == rhs); }
private:
int32_t errorCode_;
};
inline bool operator==(const ResponseCode& lhs, const KeyStoreNativeReturnCode& rhs) {
return rhs == lhs;
}
inline bool operator==(const ErrorCode& lhs, const KeyStoreNativeReturnCode& rhs) {
return rhs == lhs;
}
inline bool operator!=(const ResponseCode& lhs, const KeyStoreNativeReturnCode& rhs) {
return rhs != lhs;
}
inline bool operator!=(const ErrorCode& lhs, const KeyStoreNativeReturnCode& rhs) {
return rhs != lhs;
}
inline KeyStoreNativeReturnCode::KeyStoreNativeReturnCode(
const KeyStoreServiceReturnCode& errorCode)
: errorCode_(errorCode.getErrorCode()) {}
inline KeyStoreServiceReturnCode::KeyStoreServiceReturnCode(
const KeyStoreNativeReturnCode& errorCode)
: errorCode_(errorCode.getErrorCode()) {}
inline std::ostream& operator<<(std::ostream& out, const KeyStoreNativeReturnCode& error) {
return out << error.getErrorCode();
}
} // namespace keystore
#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_

View file

@ -1,101 +0,0 @@
// TODO: Insert description here. (generated by jdanis)
#ifndef KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_
#define KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_
#include <iterator>
#include <memory>
#include <optional>
#include <vector>
namespace android {
namespace security {
/*
* This iterator abstracts from a collection of the form
* std::shared_ptr<COLLECTION_TYPE<std::optional<T>>>
* such that it is defined both for nulled outer pointer and
* nulled entries. If shared_ptr(nullptr) is passed in, the iterator behaves
* like the end iterator yielding an empty collection. Nulled
* entries are skipped so that the iterator is always dereferencable unless
* it is equal to end.
* The default constructor always yields an iterator equal to end.
* The same iterator invalidation rules apply as they do for the iterators
* of the corresponding collection.
*/
template <typename T, template <typename...> class Coll = std::vector>
class SharedNullableIterator {
public:
typedef Coll<std::optional<typename std::remove_const<T>::type>> CollectionType;
typedef std::shared_ptr<CollectionType> CollectionPtr;
SharedNullableIterator() {}
explicit SharedNullableIterator(const std::shared_ptr<CollectionType>& coll) : coll_(coll) {
init();
}
explicit SharedNullableIterator(std::shared_ptr<CollectionType>&& coll) : coll_(coll) {
init();
}
SharedNullableIterator(const SharedNullableIterator& other)
: coll_(other.coll_), cur_(other.cur_) {}
SharedNullableIterator(SharedNullableIterator&& other) noexcept
: coll_(std::move(other.coll_)), cur_(std::move(other.cur_)) {}
SharedNullableIterator& operator++() {
inc();
return *this;
}
SharedNullableIterator operator++(int) {
SharedNullableIterator retval(*this);
++(*this);
return retval;
}
T& operator*() const { return **cur_; }
T* operator->() const { return &**cur_; }
bool operator==(const SharedNullableIterator& other) const {
return cur_ == other.cur_ || (is_end() && other.is_end());
}
bool operator!=(const SharedNullableIterator& other) const { return !(*this == other); }
SharedNullableIterator& operator=(const SharedNullableIterator&) = default;
SharedNullableIterator& operator=(SharedNullableIterator&&) noexcept = default;
private:
inline bool is_end() const { return !coll_ || cur_ == coll_->end(); }
inline void inc() {
if (!is_end()) {
do {
++cur_;
// move forward to the next non null member or stay at end
} while (cur_ != coll_->end() && !(*cur_));
}
}
void init() {
if (coll_) {
// move forward to the first non null member
for (cur_ = coll_->begin(); cur_ != coll_->end() && !(*cur_); ++cur_) {
}
}
}
CollectionPtr coll_;
typename CollectionType::iterator cur_;
};
} // namespace security
} // namespace android
namespace std {
template <typename T, template <typename...> class COLL>
struct iterator_traits<android::security::SharedNullableIterator<T, COLL>> {
typedef T& reference;
typedef T value_type;
typedef T* pointer;
typedef forward_iterator_tag iterator_category;
};
}
#endif // KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_

View file

@ -1,46 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/security/keystore/IKeystoreService.h>
#include <binder/IServiceManager.h>
#include <keystore/keystore_get.h>
#include <vector>
using namespace android;
using namespace keystore;
ssize_t keystore_get(const char* key, size_t keyLength, uint8_t** value) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
sp<android::security::keystore::IKeystoreService> service =
interface_cast<android::security::keystore::IKeystoreService>(binder);
if (service == nullptr) {
return -1;
}
::std::vector<uint8_t> result;
auto ret = service->get(String16(key, keyLength), -1, &result);
if (!ret.isOk()) return -1;
if (value) {
*value = reinterpret_cast<uint8_t*>(malloc(result.size()));
if (!*value) return -1;
memcpy(*value, &result[0], result.size());
}
return result.size();
}

View file

@ -1,107 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_
#define KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_
#include <time.h>
#include "keymaster_enforcement.h"
namespace keystore {
/**
* This is a specialization of the KeymasterEnforcement class to be used by Keystore to enforce
* keymaster requirements on all key operation.
*/
class KeystoreKeymasterEnforcement : public KeymasterEnforcement {
public:
KeystoreKeymasterEnforcement() : KeymasterEnforcement(64, 64) {}
uint32_t get_current_time() const override {
struct timespec tp;
int err = clock_gettime(CLOCK_MONOTONIC, &tp);
if (err || tp.tv_sec < 0)
return 0;
return static_cast<uint32_t>(tp.tv_sec);
}
bool activation_date_valid(uint64_t activation_date) const override {
time_t now = time(nullptr);
if (now == static_cast<time_t>(-1)) {
// Failed to obtain current time -- fail safe: activation_date hasn't yet occurred.
return false;
} else if (now < 0) {
// Current time is prior to start of the epoch -- activation_date hasn't yet occurred.
return false;
}
// time(NULL) returns seconds since epoch and "loses" milliseconds information. We thus add
// 999 ms to now_date to avoid a situation where an activation_date of up to 999ms in the
// past may still be considered to still be in the future. This can be removed once
// time(NULL) is replaced by a millisecond-precise source of time.
uint64_t now_date = static_cast<uint64_t>(now) * 1000 + 999;
return now_date >= activation_date;
}
bool expiration_date_passed(uint64_t expiration_date) const override {
time_t now = time(nullptr);
if (now == static_cast<time_t>(-1)) {
// Failed to obtain current time -- fail safe: expiration_date has passed.
return true;
} else if (now < 0) {
// Current time is prior to start of the epoch: expiration_date hasn't yet occurred.
return false;
}
// time(NULL) returns seconds since epoch and "loses" milliseconds information. As a result,
// expiration_date of up to 999 ms in the past may still be considered in the future. This
// is OK.
uint64_t now_date = static_cast<uint64_t>(now) * 1000;
return now_date > expiration_date;
}
bool auth_token_timed_out(const HardwareAuthToken&, uint32_t) const {
// Assume the token has not timed out, because AuthTokenTable would not have returned it if
// the timeout were past. Secure hardware will also check timeouts if it supports them.
return false;
}
bool ValidateTokenSignature(const HardwareAuthToken&) const override {
// Non-secure world cannot validate token signatures because it doesn't have access to the
// signing key. Assume the token is good.
return true;
}
bool is_device_locked(int32_t userId) const override {
std::lock_guard<std::mutex> lock(is_device_locked_for_user_map_lock_);
// If we haven't had a set call for this user yet, assume the device is locked.
if (mIsDeviceLockedForUser.count(userId) == 0) return true;
return mIsDeviceLockedForUser.find(userId)->second;
}
void set_device_locked(bool isLocked, int32_t userId) {
std::lock_guard<std::mutex> lock(is_device_locked_for_user_map_lock_);
mIsDeviceLockedForUser[userId] = isLocked;
}
private:
mutable std::mutex is_device_locked_for_user_map_lock_;
std::map<int32_t, bool> mIsDeviceLockedForUser;
};
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_

View file

@ -1,179 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "keystore"
#include "keystore_utils.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include <log/log_event_list.h>
#include <keystore/keymaster_types.h>
#include <keystore/keystore_client.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include "blob.h"
size_t readFully(int fd, uint8_t* data, size_t size) {
size_t remaining = size;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, remaining));
if (n <= 0) {
return size - remaining;
}
data += n;
remaining -= n;
}
return size;
}
size_t writeFully(int fd, uint8_t* data, size_t size) {
size_t remaining = size;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, remaining));
if (n < 0) {
ALOGW("write failed: %s", strerror(errno));
return size - remaining;
}
data += n;
remaining -= n;
}
if (TEMP_FAILURE_RETRY(fsync(fd)) == -1) {
ALOGW("fsync failed: %s", strerror(errno));
return -1;
}
return size;
}
std::string getContainingDirectory(const std::string& filename) {
std::string containing_dir;
size_t last_pos;
size_t pos = std::string::npos;
__builtin_add_overflow(filename.size(), -1, &last_pos);
// strip all trailing '/'
while ((pos = filename.find_last_of('/', last_pos)) == last_pos && pos != 0) {
--last_pos;
}
if (pos == 0) {
containing_dir = "/";
} else if (pos == std::string::npos) {
containing_dir = ".";
} else {
containing_dir = filename.substr(0, pos);
}
return containing_dir;
}
void fsyncDirectory(const std::string& path) {
android::base::unique_fd dir_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_DIRECTORY | O_RDONLY)));
if (dir_fd < 0) {
LOG(WARNING) << "Could not open dir: " << path << " error: " << strerror(errno);
return;
}
if (TEMP_FAILURE_RETRY(fsync(dir_fd)) == -1) {
LOG(WARNING) << "Failed to fsync the directory " << path << " error: " << strerror(errno);
}
return;
}
void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params) {
using namespace keystore;
params->push_back(TAG_PURPOSE, KeyPurpose::SIGN);
params->push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
params->push_back(TAG_PURPOSE, KeyPurpose::ENCRYPT);
params->push_back(TAG_PURPOSE, KeyPurpose::DECRYPT);
params->push_back(TAG_PADDING, PaddingMode::NONE);
if (keyType == EVP_PKEY_RSA) {
params->push_back(TAG_PADDING, PaddingMode::RSA_PKCS1_1_5_SIGN);
params->push_back(TAG_PADDING, PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
params->push_back(TAG_PADDING, PaddingMode::RSA_PSS);
params->push_back(TAG_PADDING, PaddingMode::RSA_OAEP);
}
params->push_back(TAG_DIGEST, Digest::NONE);
params->push_back(TAG_DIGEST, Digest::MD5);
params->push_back(TAG_DIGEST, Digest::SHA1);
params->push_back(TAG_DIGEST, Digest::SHA_2_224);
params->push_back(TAG_DIGEST, Digest::SHA_2_256);
params->push_back(TAG_DIGEST, Digest::SHA_2_384);
params->push_back(TAG_DIGEST, Digest::SHA_2_512);
params->push_back(TAG_NO_AUTH_REQUIRED);
params->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, LLONG_MAX);
params->push_back(TAG_USAGE_EXPIRE_DATETIME, LLONG_MAX);
params->push_back(TAG_ACTIVE_DATETIME, 0);
}
uid_t get_app_id(uid_t uid) {
return uid % AID_USER;
}
uid_t get_user_id(uid_t uid) {
return uid / AID_USER;
}
void log_key_integrity_violation(const char* name, uid_t uid) {
if (!__android_log_security()) return;
android_log_event_list(SEC_TAG_KEY_INTEGRITY_VIOLATION)
<< name << int32_t(uid) << LOG_ID_SECURITY;
}
namespace keystore {
hidl_vec<uint8_t> blob2hidlVec(const Blob& blob) {
hidl_vec<uint8_t> result(blob.getValue(), blob.getValue() + blob.getLength());
return result;
}
SecurityLevel flagsToSecurityLevel(int32_t flags) {
switch (flags & (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX)) {
case KEYSTORE_FLAG_FALLBACK:
// treating Strongbox flag as "don't care" if Fallback is set
case (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX):
return SecurityLevel::SOFTWARE;
case KEYSTORE_FLAG_STRONGBOX:
return SecurityLevel::STRONGBOX;
default:
return SecurityLevel::TRUSTED_ENVIRONMENT;
}
}
uint32_t securityLevelToFlags(SecurityLevel secLevel) {
switch (secLevel) {
case SecurityLevel::SOFTWARE:
return KEYSTORE_FLAG_FALLBACK;
case SecurityLevel::STRONGBOX:
return KEYSTORE_FLAG_STRONGBOX;
default:
return 0;
}
}
} // namespace keystore

View file

@ -1,70 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef KEYSTORE_KEYSTORE_UTILS_H_
#define KEYSTORE_KEYSTORE_UTILS_H_
#include <cstdint>
#include <string>
#include <vector>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <memory>
#include <keystore/keymaster_types.h>
size_t readFully(int fd, uint8_t* data, size_t size);
size_t writeFully(int fd, uint8_t* data, size_t size);
std::string getContainingDirectory(const std::string& filename);
void fsyncDirectory(const std::string& path);
void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params);
/**
* Returns the app ID (in the Android multi-user sense) for the current
* UNIX UID.
*/
uid_t get_app_id(uid_t uid);
/**
* Returns the user ID (in the Android multi-user sense) for the current
* UNIX UID.
*/
uid_t get_user_id(uid_t uid);
class Blob;
// Tags for audit logging. Be careful and don't log sensitive data.
// Should be in sync with frameworks/base/core/java/android/app/admin/SecurityLogTags.logtags
constexpr int SEC_TAG_KEY_DESTROYED = 210026;
constexpr int SEC_TAG_KEY_INTEGRITY_VIOLATION = 210032;
constexpr int SEC_TAG_AUTH_KEY_GENERATED = 210024;
constexpr int SEC_TAG_KEY_IMPORTED = 210025;
void log_key_integrity_violation(const char* name, uid_t uid);
namespace keystore {
hidl_vec<uint8_t> blob2hidlVec(const Blob& blob);
SecurityLevel flagsToSecurityLevel(int32_t flags);
uint32_t securityLevelToFlags(SecurityLevel secLevel);
} // namespace keystore
#endif // KEYSTORE_KEYSTORE_UTILS_H_

View file

@ -1,273 +0,0 @@
#!/bin/bash
#
# Copyright 2011, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
prefix=$0
log_file=$prefix.log
baseline_file=$prefix.baseline
function cleanup_output() {
rm -f $log_file
rm -f $baseline_file
}
function log() {
echo "$@"
append $log_file \# "$@"
append $baseline_file \# "$@"
}
function expect() {
append $baseline_file "$@"
}
function append() {
declare -r file=$1
shift
echo "$@" >> $file
}
function run() {
# strip out carriage returns from adb
# strip out date/time from ls -l
"$@" | tr --delete '\r' | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} +[0-9]{1,2}:[0-9]{2} //' >> $log_file
}
function keystore() {
declare -r user=$1
shift
run adb shell su $user keystore_cli "$@"
}
function list_keystore_directory() {
run adb shell ls -al /data/misc/keystore
}
function compare() {
log "comparing $baseline_file and $log_file"
diff $baseline_file $log_file || (log $tag FAILED && exit 1)
}
function test_basic() {
#
# reset
#
log "reset keystore as system user"
keystore system r
expect "1 No error"
list_keystore_directory
#
# basic tests as system/root
#
log "root does not have permission to run test"
keystore root t
expect "6 Permission denied"
log "but system user does"
keystore system t
expect "3 Uninitialized"
list_keystore_directory
log "password is now bar"
keystore system p bar
expect "1 No error"
list_keystore_directory
expect "-rw------- keystore keystore 84 .masterkey"
log "no error implies initialized and unlocked"
keystore system t
expect "1 No error"
log "saw with no argument"
keystore system s
expect "5 Protocol error"
log "saw nothing"
keystore system s ""
expect "1 No error"
log "add key baz"
keystore system i baz quux
expect "1 No error"
log "1000 is uid of system"
list_keystore_directory
expect "-rw------- keystore keystore 84 .masterkey"
expect "-rw------- keystore keystore 52 1000_baz"
log "saw baz"
keystore system s ""
expect "1 No error"
expect "baz"
log "get baz"
keystore system g baz
expect "1 No error"
expect "quux"
log "root can read system user keys (as can wifi or vpn users)"
keystore root g baz
expect "1 No error"
expect "quux"
#
# app user tests
#
# app_0 has uid 10000, as seen below
log "other uses cannot see the system keys"
keystore app_0 g baz
expect "7 Key not found"
log "app user cannot use reset, password, lock, unlock"
keystore app_0 r
expect "6 Permission denied"
keystore app_0 p
expect "6 Permission denied"
keystore app_0 l
expect "6 Permission denied"
keystore app_0 u
expect "6 Permission denied"
log "install app_0 key"
keystore app_0 i 0x deadbeef
expect 1 No error
list_keystore_directory
expect "-rw------- keystore keystore 84 .masterkey"
expect "-rw------- keystore keystore 52 10000_0x"
expect "-rw------- keystore keystore 52 1000_baz"
log "get with no argument"
keystore app_0 g
expect "5 Protocol error"
keystore app_0 g 0x
expect "1 No error"
expect "deadbeef"
keystore app_0 i fred barney
expect "1 No error"
keystore app_0 s ""
expect "1 No error"
expect "0x"
expect "fred"
log "note that saw returns the suffix of prefix matches"
keystore app_0 s fr # fred
expect "1 No error"
expect "ed" # fred
#
# lock tests
#
log "lock the store as system"
keystore system l
expect "1 No error"
keystore system t
expect "2 Locked"
log "saw works while locked"
keystore app_0 s ""
expect "1 No error"
expect "0x"
expect "fred"
log "...but cannot read keys..."
keystore app_0 g 0x
expect "2 Locked"
log "...but they can be deleted."
keystore app_0 e 0x
expect "1 No error"
keystore app_0 d 0x
expect "1 No error"
keystore app_0 e 0x
expect "7 Key not found"
#
# password
#
log "wrong password"
keystore system u foo
expect "13 Wrong password (4 tries left)"
log "right password"
keystore system u bar
expect "1 No error"
log "make the password foo"
keystore system p foo
expect "1 No error"
#
# final reset
#
log "reset wipes everything for all users"
keystore system r
expect "1 No error"
list_keystore_directory
keystore system t
expect "3 Uninitialized"
}
function test_4599735() {
# http://b/4599735
log "start regression test for b/4599735"
keystore system r
expect "1 No error"
keystore system p foo
expect "1 No error"
keystore system i baz quux
expect "1 No error"
keystore root g baz
expect "1 No error"
expect "quux"
keystore system l
expect "1 No error"
keystore system p foo
expect "1 No error"
log "after unlock, regression led to result of '8 Value corrupted'"
keystore root g baz
expect "1 No error"
expect "quux"
keystore system r
expect "1 No error"
log "end regression test for b/4599735"
}
function main() {
cleanup_output
log $tag START
test_basic
test_4599735
compare
log $tag PASSED
cleanup_output
}
main

View file

@ -1,125 +0,0 @@
##########
# This makefile builds local unit tests that run locally on the development machine. Note
# that it may be necessary to install some libraries on the dev maching to make the tests
# build.
#
# The same unit tests are also built by Android.mk to run on the target device. The tests
# should always build and pass in both places. The on-device test is what really matters,
# of course, but debugging is often somewhat easier on the dev platform.
##########
BASE=../../../..
SUBS=system/core \
system/keymaster\
hardware/libhardware \
external/gtest
GTEST=$(BASE)/external/gtest
KEYMASTER=$(BASE)/system/keymaster
INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
-I $(GTEST) -Iinclude
# Add USE_CLANG=1 to the make command line to build with clang, which has better error
# reporting and diagnoses some conditions that GCC doesn't.
ifdef USE_CLANG
CC=/usr/bin/clang
CXX=/usr/bin/clang
CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
else
COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
endif
CPPFLAGS=$(INCLUDES) -g -O0 -MD -DHOST_BUILD
CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
-Werror=sign-compare -Wmissing-declarations -ftest-coverage -fno-permissive \
-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
$(COMPILER_SPECIFIC_ARGS)
# Uncomment to enable debug logging.
# CXXFLAGS += -DDEBUG
LDLIBS=-lpthread -lstdc++ -lgcov
# This list of sources is used for dependency generation and cleanup. Add each new source
# file here (not headers).
CPPSRCS=\
../auth_token_table.cpp \
auth_token_table_test.cpp \
gtest_main.cpp \
$(KEYMASTER)/authorization_set.cpp \
$(KEYMASTER)/keymaster_tags.cpp \
$(KEYMASTER)/logger.cpp \
$(KEYMASTER)/serializable.cpp
CCSRCS=$(GTEST)/src/gtest-all.cc
# This list of binaries determes what gets built and run. Add each new test binary here.
BINARIES=\
auth_token_table_test
.PHONY: coverage memcheck massif clean run
%.run: %
./$<
touch $@
run: $(BINARIES:=.run)
GTEST_OBJS = $(GTEST)/src/gtest-all.o gtest_main.o
auth_token_table_test: auth_token_table_test.o \
../auth_token_table.o \
$(GTEST_OBJS) \
$(KEYMASTER)/authorization_set.o \
$(KEYMASTER)/keymaster_tags.o \
$(KEYMASTER)/logger.o \
$(KEYMASTER)/serializable.o
coverage: coverage.info
genhtml coverage.info --output-directory coverage
coverage.info: run
lcov --capture --directory=. --directory=.. -b . --output-file coverage.info
%.coverage : %
$(MAKE) clean && $(MAKE) $<
./$<
lcov --capture --directory=. --output-file coverage.info
genhtml coverage.info --output-directory coverage
#UNINIT_OPTS=--track-origins=yes
UNINIT_OPTS=--undef-value-errors=no
MEMCHECK_OPTS=--leak-check=full \
--show-reachable=yes \
--vgdb=full \
$(UNINIT_OPTS) \
--error-exitcode=1
MASSIF_OPTS=--tool=massif \
--stacks=yes
%.memcheck : %
valgrind $(MEMCHECK_OPTS) ./$< && \
touch $@
%.massif : %
valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
memcheck: $(BINARIES:=.memcheck)
massif: $(BINARIES:=.massif)
OBJS=$(CPPSRCS:.cpp=.o)
DEPS=$(CPPSRCS:.cpp=.d)
GCOV=$(CPPSRCS:.cpp=.gcov) $(CPPSRCS:.cpp=.gcda) $(CPPSRCS:.cpp=.gcno)
clean:
rm -f $(OBJS) $(DEPS) $(BINARIES) $(GCOV) \
$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
*gcov *gcno *gcda coverage.info
rm -rf coverage
-include $(CPPSRCS:.cpp=.d)
-include $(CCSRCS:.cc=.d)

View file

@ -1,157 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <endian.h>
#include <hidl/HidlSupport.h>
#include <keymaster/logger.h>
#include <keymasterV4_0/keymaster_utils.h>
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
#include "../auth_token_table.h"
using std::vector;
namespace keystore {
using android::hardware::hidl_array;
using android::hardware::hidl_vec;
namespace test {
namespace {
class StdoutLogger : public ::keymaster::Logger {
public:
StdoutLogger() { set_instance(this); }
int log_msg(LogLevel level, const char* fmt, va_list args) const {
int output_len = 0;
switch (level) {
case DEBUG_LVL:
output_len = printf("DEBUG: ");
break;
case INFO_LVL:
output_len = printf("INFO: ");
break;
case WARNING_LVL:
output_len = printf("WARNING: ");
break;
case ERROR_LVL:
output_len = printf("ERROR: ");
break;
case SEVERE_LVL:
output_len = printf("SEVERE: ");
break;
}
output_len += vprintf(fmt, args);
output_len += printf("\n");
return output_len;
}
};
StdoutLogger logger;
} // namespace
constexpr const uint8_t test_token[69] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44};
constexpr const uint8_t test_hmac_data[] = {
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44};
static const Km3HardwareAuthToken km3_hidl_test_token_little_endian = {
UINT64_C(0x0807060504030201), UINT64_C(0x100f0e0d0c0b0a09),
UINT64_C(0x1817161514131211), UINT32_C(0x1c1b1a19),
UINT64_C(0x24232221201f1e1d), hidl_array<uint8_t, 32>(test_hmac_data)};
static const HardwareAuthToken km4_hidl_test_token = {
UINT64_C(0x0807060504030201), UINT64_C(0x100f0e0d0c0b0a09),
UINT64_C(0x1817161514131211), static_cast<HardwareAuthenticatorType>(UINT32_C(0x191a1b1c)),
UINT64_C(0x1d1e1f2021222324), hidl_vec<uint8_t>(test_hmac_data, test_hmac_data + 32)};
TEST(AuthenticationTokenFormattingTest, hidlVec2Km3AuthToken) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(km3_hidl_test_token_little_endian, hidlVec2Km3AuthToken(hidl_test_token));
}
TEST(AuthenticationTokenFormattingTest, hidlVec2Km4AuthToken) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(km4_hidl_test_token, hidlVec2AuthToken(hidl_test_token));
}
TEST(AuthenticationTokenFormattingTest, km3AuthToken2HidlVec) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(hidl_test_token, authToken2HidlVec(km3_hidl_test_token_little_endian));
}
TEST(AuthenticationTokenFormattingTest, km4AuthToken2HidlVec) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(hidl_test_token, authToken2HidlVec(km4_hidl_test_token));
}
TEST(AuthenticationTokenFormattingTest, backAndForth) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(km3_hidl_test_token_little_endian,
hidlVec2Km3AuthToken(authToken2HidlVec(km3_hidl_test_token_little_endian)));
ASSERT_EQ(km4_hidl_test_token, hidlVec2AuthToken(authToken2HidlVec(km4_hidl_test_token)));
}
TEST(AuthenticationTokenFormattingTest, forthAndBack) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
ASSERT_EQ(hidl_test_token, authToken2HidlVec(hidlVec2Km3AuthToken(hidl_test_token)));
ASSERT_EQ(hidl_test_token, authToken2HidlVec(hidlVec2Km3AuthToken(hidl_test_token)));
}
TEST(AuthenticationTokenFormattingTest, roundAndRound) {
static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size");
hidl_vec<uint8_t> hidl_test_token;
hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token));
HardwareAuthToken km4_from_hidl = hidlVec2AuthToken(hidl_test_token);
hidl_vec<uint8_t> hidl_from_km4 = authToken2HidlVec(km4_from_hidl);
Km3HardwareAuthToken km3_from_hidl = hidlVec2Km3AuthToken(hidl_from_km4);
hidl_vec<uint8_t> hidl_from_km3 = authToken2HidlVec(km3_from_hidl);
ASSERT_EQ(hidl_from_km4, hidl_test_token);
ASSERT_EQ(hidl_from_km3, hidl_test_token);
ASSERT_NE(km4_from_hidl.timestamp, km3_from_hidl.timestamp);
ASSERT_NE(static_cast<uint32_t>(km4_from_hidl.authenticatorType),
km3_from_hidl.authenticatorType);
}
} // namespace test
} // namespace keystore

View file

@ -1,520 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <endian.h>
#include <keymaster/logger.h>
#include "../auth_token_table.h"
using std::vector;
namespace keystore {
namespace test {
class StdoutLogger : public ::keymaster::Logger {
public:
StdoutLogger() { set_instance(this); }
int log_msg(LogLevel level, const char* fmt, va_list args) const {
int output_len = 0;
switch (level) {
case DEBUG_LVL:
output_len = printf("DEBUG: ");
break;
case INFO_LVL:
output_len = printf("INFO: ");
break;
case WARNING_LVL:
output_len = printf("WARNING: ");
break;
case ERROR_LVL:
output_len = printf("ERROR: ");
break;
case SEVERE_LVL:
output_len = printf("SEVERE: ");
break;
}
output_len += vprintf(fmt, args);
output_len += printf("\n");
return output_len;
}
};
StdoutLogger logger;
TEST(AuthTokenTableTest, Create) {
AuthTokenTable table;
}
static HardwareAuthToken make_token(uint64_t rsid, uint64_t ssid = 0, uint64_t challenge = 0,
uint64_t timestamp = 0) {
HardwareAuthToken token;
token.userId = rsid;
token.authenticatorId = ssid;
token.authenticatorType = HardwareAuthenticatorType::PASSWORD;
token.challenge = challenge;
token.timestamp = timestamp;
return token;
}
static AuthorizationSet make_set(uint64_t rsid, uint32_t timeout = 10000) {
AuthorizationSetBuilder builder;
builder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD)
.Authorization(TAG_USER_SECURE_ID, rsid);
// Use timeout == 0 to indicate tags that require auth per operation.
if (timeout != 0) builder.Authorization(TAG_AUTH_TIMEOUT, timeout);
return std::move(builder);
}
// Tests obviously run so fast that a real-time clock with a one-second granularity rarely changes
// output during a test run. This test clock "ticks" one second every time it's called.
static time_t monotonic_clock() {
static time_t time = 0;
return time++;
}
TEST(AuthTokenTableTest, SimpleAddAndFindTokens) {
AuthTokenTable table;
table.AddAuthenticationToken(make_token(1, 2));
table.AddAuthenticationToken(make_token(3, 4));
EXPECT_EQ(2U, table.size());
AuthTokenTable::Error rc;
HardwareAuthToken found;
ASSERT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(1U, found.userId);
EXPECT_EQ(2U, found.authenticatorId);
ASSERT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(1U, found.userId);
EXPECT_EQ(2U, found.authenticatorId);
ASSERT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(3U, found.userId);
EXPECT_EQ(4U, found.authenticatorId);
ASSERT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(3U, found.userId);
EXPECT_EQ(4U, found.authenticatorId);
ASSERT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
}
TEST(AuthTokenTableTest, FlushTable) {
AuthTokenTable table(3, monotonic_clock);
table.AddAuthenticationToken(make_token(1));
table.AddAuthenticationToken(make_token(2));
table.AddAuthenticationToken(make_token(3));
AuthTokenTable::Error rc;
HardwareAuthToken found;
// All three should be in the table.
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.Clear();
EXPECT_EQ(0U, table.size());
}
TEST(AuthTokenTableTest, TableOverflow) {
AuthTokenTable table(3, monotonic_clock);
table.AddAuthenticationToken(make_token(1));
table.AddAuthenticationToken(make_token(2));
table.AddAuthenticationToken(make_token(3));
AuthTokenTable::Error rc;
HardwareAuthToken found;
// All three should be in the table.
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(4));
// Oldest should be gone.
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
// Others should be there, including the new one (4). Search for it first, then the others, so
// 4 becomes the least recently used.
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(5));
// 5 should have replaced 4.
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(6));
table.AddAuthenticationToken(make_token(7));
// 2 and 5 should be gone
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(8));
table.AddAuthenticationToken(make_token(9));
table.AddAuthenticationToken(make_token(10));
// Only the three most recent should be there.
EXPECT_EQ(3U, table.size());
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(8), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(9), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(10), KeyPurpose::SIGN, 0), rc));
}
TEST(AuthTokenTableTest, AuthenticationNotRequired) {
AuthTokenTable table;
AuthTokenTable::Error rc;
HardwareAuthToken found;
EXPECT_EQ(AuthTokenTable::AUTH_NOT_REQUIRED,
(std::tie(rc, found) = table.FindAuthorization(
AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED), KeyPurpose::SIGN,
0 /* no challenge */),
rc));
}
TEST(AuthTokenTableTest, OperationHandleNotFound) {
AuthTokenTable table;
AuthTokenTable::Error rc;
HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1, 0, 1, 5));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) =
table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
2 /* non-matching challenge */),
rc));
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(
make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* matching challenge */),
rc));
table.MarkCompleted(1);
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(
make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* used challenge */),
rc));
}
TEST(AuthTokenTableTest, OperationHandleRequired) {
AuthTokenTable table;
AuthTokenTable::Error rc;
HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1));
EXPECT_EQ(AuthTokenTable::OP_HANDLE_REQUIRED,
(std::tie(rc, found) = table.FindAuthorization(
make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 0 /* no op handle */),
rc));
}
TEST(AuthTokenTableTest, AuthSidChanged) {
AuthTokenTable table;
AuthTokenTable::Error rc;
HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1, 3, /* op handle */ 1));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_WRONG_SID,
(std::tie(rc, found) = table.FindAuthorization(make_set(2, 0 /* no timeout */),
KeyPurpose::SIGN, 1 /* op handle */),
rc));
}
TEST(AuthTokenTableTest, TokenExpired) {
AuthTokenTable table(5, monotonic_clock);
AuthTokenTable::Error rc;
HardwareAuthToken found;
auto key_info = make_set(1, 5 /* five second timeout */);
// monotonic_clock "ticks" one second each time it's called, which is once per request, so the
// sixth request should fail, since key_info says the key is good for five seconds.
//
// Note that this tests the decision of the AuthTokenTable to reject a request it knows is
// expired. An additional check of the secure timestamp (in the token) will be made by
// keymaster when the found token is passed to it.
table.AddAuthenticationToken(make_token(1, 0));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_EXPIRED,
(std::tie(rc, found) =
table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */),
rc));
}
TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) {
AuthTokenTable table;
// Marking a nonexistent entry completed is ignored. This test is mainly for code coverage.
table.MarkCompleted(1);
}
TEST(AuthTokenTableTest, SupersededEntries) {
AuthTokenTable table;
AuthTokenTable::Error rc;
HardwareAuthToken found;
// Add two identical tokens, without challenges. The second should supersede the first, based
// on timestamp (fourth arg to make_token).
table.AddAuthenticationToken(make_token(1, 0, 0, 0));
table.AddAuthenticationToken(make_token(1, 0, 0, 1));
EXPECT_EQ(1U, table.size());
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(1U, found.timestamp);
// Add a third token, this with a different RSID. It should not be superseded.
table.AddAuthenticationToken(make_token(2, 0, 0, 2));
EXPECT_EQ(2U, table.size());
// Add two more, superseding each of the two in the table.
table.AddAuthenticationToken(make_token(1, 0, 0, 3));
table.AddAuthenticationToken(make_token(2, 0, 0, 4));
EXPECT_EQ(2U, table.size());
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(3U, found.timestamp);
EXPECT_EQ(
AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
EXPECT_EQ(4U, found.timestamp);
// Add another, this one with a challenge value. It should supersede the old one since it is
// newer, and matches other than the challenge.
table.AddAuthenticationToken(make_token(1, 0, 1, 5));
EXPECT_EQ(2U, table.size());
// And another, also with a challenge. Because of the challenge values, the one just added
// cannot be superseded.
table.AddAuthenticationToken(make_token(1, 0, 2, 6));
EXPECT_EQ(3U, table.size());
// Should be able to find each of them, by specifying their challenge, with a key that is not
// timed (timed keys don't care about challenges).
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout*/),
KeyPurpose::SIGN, 1 /* challenge */),
rc));
EXPECT_EQ(5U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 2 /* challenge */),
rc));
EXPECT_EQ(6U, found.timestamp);
// Add another, without a challenge, and the same timestamp as the last one. This new one
// actually could be considered already-superseded, but the table doesn't handle that case,
// since it seems unlikely to occur in practice.
table.AddAuthenticationToken(make_token(1, 0, 0, 6));
EXPECT_EQ(4U, table.size());
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(6U, found.timestamp);
// Add another without a challenge but an increased timestamp. This should supersede the
// previous challenge-free entry.
table.AddAuthenticationToken(make_token(1, 0, 0, 7));
EXPECT_EQ(4U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 2 /* challenge */),
rc));
EXPECT_EQ(6U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(7U, found.timestamp);
// Mark the entry with challenge 2 as complete. Since there's a newer challenge-free entry, the
// challenge entry will be superseded.
table.MarkCompleted(2);
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 2 /* challenge */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(7U, found.timestamp);
// Add another SID 1 entry with a challenge. It supersedes the previous SID 1 entry with
// no challenge (timestamp 7), but not the one with challenge 1 (timestamp 5).
table.AddAuthenticationToken(make_token(1, 0, 3, 8));
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 1 /* challenge */),
rc));
EXPECT_EQ(5U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 3 /* challenge */),
rc));
EXPECT_EQ(8U, found.timestamp);
// SID 2 entry is still there.
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(2), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(4U, found.timestamp);
// Mark the entry with challenge 3 as complete. Since the older challenge 1 entry is
// incomplete, nothing is superseded.
table.MarkCompleted(3);
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 1 /* challenge */),
rc));
EXPECT_EQ(5U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(8U, found.timestamp);
// Mark the entry with challenge 1 as complete. Since there's a newer one (with challenge 3,
// completed), the challenge 1 entry is superseded and removed.
table.MarkCompleted(1);
EXPECT_EQ(2U, table.size());
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
(std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
KeyPurpose::SIGN, 1 /* challenge */),
rc));
EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
rc));
EXPECT_EQ(8U, found.timestamp);
}
} // namespace test
} // namespace keystore

View file

@ -1,274 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "../confirmationui_rate_limiting.h"
#include <keymaster/logger.h>
using std::vector;
namespace keystore {
namespace test {
namespace {
class StdoutLogger : public ::keymaster::Logger {
public:
StdoutLogger() { set_instance(this); }
int log_msg(LogLevel level, const char* fmt, va_list args) const {
int output_len = 0;
switch (level) {
case DEBUG_LVL:
output_len = printf("DEBUG: ");
break;
case INFO_LVL:
output_len = printf("INFO: ");
break;
case WARNING_LVL:
output_len = printf("WARNING: ");
break;
case ERROR_LVL:
output_len = printf("ERROR: ");
break;
case SEVERE_LVL:
output_len = printf("SEVERE: ");
break;
}
output_len += vprintf(fmt, args);
output_len += printf("\n");
return output_len;
}
};
StdoutLogger logger;
class FakeClock : public std::chrono::steady_clock {
private:
static time_point sNow;
public:
static void setNow(time_point newNow) { sNow = newNow; }
static time_point now() noexcept { return sNow; }
};
FakeClock::time_point FakeClock::sNow;
} // namespace
/*
* Test that there are no residual slots when various apps receive successful confirmations.
*/
TEST(ConfirmationUIRateLimitingTest, noPenaltyTest) {
auto now = std::chrono::steady_clock::now();
RateLimiting<FakeClock> rateLimiting;
FakeClock::setNow(now);
for (int i = 0; i < 10000; ++i) {
ASSERT_TRUE(rateLimiting.tryPrompt(rand()));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
ASSERT_EQ(0U, rateLimiting.usedSlots());
}
TEST(ConfirmationUIRateLimitingTest, policyTest) {
using namespace std::chrono_literals;
auto now = std::chrono::steady_clock::now();
RateLimiting<FakeClock> rateLimiting;
FakeClock::setNow(now);
// first three tries are free
for (int i = 0; i < 3; ++i) {
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
// the next three tries get a 30s penalty
for (int i = 3; i < 6; ++i) {
FakeClock::setNow(FakeClock::now() + 29s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
// there after the penalty doubles with each cancellation
for (int i = 6; i < 17; ++i) {
FakeClock::setNow((FakeClock::now() + 60s * (1ULL << (i - 6))) - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
ASSERT_EQ(1U, rateLimiting.usedSlots());
FakeClock::setNow(FakeClock::now() + 24h - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
// after 24h the counter is forgotten
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
for (int i = 1; i < 3; ++i) {
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
for (int i = 3; i < 6; ++i) {
FakeClock::setNow(FakeClock::now() + 29s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
for (int i = 6; i < 17; ++i) {
FakeClock::setNow((FakeClock::now() + 60s * (1ULL << (i - 6))) - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
ASSERT_EQ(1U, rateLimiting.usedSlots());
}
TEST(ConfirmationUIRateLimitingTest, rewindTest) {
using namespace std::chrono_literals;
auto now = std::chrono::steady_clock::now();
RateLimiting<FakeClock> rateLimiting;
// first three tries are free
for (int i = 0; i < 3; ++i) {
FakeClock::setNow(now);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
for (int i = 3; i < 6; ++i) {
FakeClock::setNow(FakeClock::now() + 29s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Canceled);
}
FakeClock::setNow(FakeClock::now() + 59s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::Aborted);
FakeClock::setNow(FakeClock::now() - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::SystemError);
// throw in a couple of successful confirmations by other apps to make sure there
// is not cross talk
for (int i = 0; i < 10000; ++i) {
uid_t id = rand();
if (id == 20) continue;
ASSERT_TRUE(rateLimiting.tryPrompt(id));
rateLimiting.processResult(ConfirmationResponseCode::OK);
}
FakeClock::setNow(FakeClock::now() - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
rateLimiting.processResult(ConfirmationResponseCode::UIError);
FakeClock::setNow(FakeClock::now() - 1s);
ASSERT_FALSE(rateLimiting.tryPrompt(20));
FakeClock::setNow(FakeClock::now() + 1s);
ASSERT_TRUE(rateLimiting.tryPrompt(20));
ASSERT_EQ(1U, rateLimiting.usedSlots());
}
} // namespace test
} // namespace keystore

View file

@ -1,77 +0,0 @@
#!/usr/bin/env bash
#
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Simple adb based test for keystore method list_auth_bound_keys
# Depends on keystore_cli_v2 tool and root
#
set -e
ROOT_ID=0
USER1_ID=10901
USER2_ID=10902
SYSTEM_ID=1000
function cli {
adb shell "su $1 keystore_cli_v2 $2"
}
#start as root
adb root
# generate keys as user
echo "generating keys"
cli $USER1_ID "delete --name=no_auth_key" || true
cli $USER1_ID "generate --name=no_auth_key"
cli $USER2_ID "delete --name=auth_key" || true
if ! cli $USER2_ID "generate --name=auth_key --auth_bound"; then
echo "Unable to generate auth bound key, make sure device/emulator has a pin/password set."
echo "$ adb shell locksettings set-pin 1234"
exit 1
fi
# try to list keys as user
if cli $USER2_ID list-apps-with-keys; then
echo "Error: list-apps-with-keys succeeded as user, this is not expected!"
exit 1
fi
# try to list keys as root
if cli $ROOT_ID "list-apps-with-keys"; then
echo "Error: list-apps-with-keys succeeded as root, this is not expected!"
exit 1
fi
# try to list keys as system
success=false
while read -r line; do
echo $line
if [ "$line" == "$USER2_ID" ]; then
success=true
fi
if [ "$line" == "$USER1_ID" ]; then
echo "Error: User1 id not expected in list"
exit 1
fi
done <<< $(cli $SYSTEM_ID "list-apps-with-keys")
if [ $success = true ]; then
echo "Success!"
else
echo "Error: User2 id not in list"
exit 1
fi

View file

@ -1,311 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "keystore"
#include "user_state.h"
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <openssl/digest.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <log/log.h>
#include "blob.h"
#include "keystore_utils.h"
namespace keystore {
UserState::UserState(uid_t userId)
: mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
mUserId(userId), mState(STATE_UNINITIALIZED) {}
bool UserState::operator<(const UserState& rhs) const {
return getUserId() < rhs.getUserId();
}
bool UserState::operator<(uid_t userId) const {
return getUserId() < userId;
}
bool operator<(uid_t userId, const UserState& rhs) {
return userId < rhs.getUserId();
}
bool UserState::initialize() {
if ((mkdir(mMasterKeyEntry.user_dir().c_str(), S_IRUSR | S_IWUSR | S_IXUSR) < 0) &&
(errno != EEXIST)) {
ALOGE("Could not create directory '%s'", mMasterKeyEntry.user_dir().c_str());
return false;
}
if (mMasterKeyEntry.hasKeyBlob()) {
setState(STATE_LOCKED);
} else {
setState(STATE_UNINITIALIZED);
}
return true;
}
void UserState::setState(State state) {
mState = state;
}
void UserState::zeroizeMasterKeysInMemory() {
memset(mMasterKey.data(), 0, mMasterKey.size());
memset(mSalt, 0, sizeof(mSalt));
}
bool UserState::deleteMasterKey() {
setState(STATE_UNINITIALIZED);
zeroizeMasterKeysInMemory();
return unlink(mMasterKeyEntry.getKeyBlobPath().c_str()) == 0 || errno == ENOENT;
}
ResponseCode UserState::initialize(const android::String8& pw) {
if (!generateMasterKey()) {
return ResponseCode::SYSTEM_ERROR;
}
ResponseCode response = writeMasterKey(pw);
if (response != ResponseCode::NO_ERROR) {
return response;
}
setupMasterKeys();
return ResponseCode::NO_ERROR;
}
ResponseCode UserState::copyMasterKey(LockedUserState<UserState>* src) {
if (mState != STATE_UNINITIALIZED) {
return ResponseCode::SYSTEM_ERROR;
}
if ((*src)->getState() != STATE_NO_ERROR) {
return ResponseCode::SYSTEM_ERROR;
}
mMasterKey = (*src)->mMasterKey;
setupMasterKeys();
return copyMasterKeyFile(src);
}
ResponseCode UserState::copyMasterKeyFile(LockedUserState<UserState>* src) {
/* Copy the master key file to the new user. Unfortunately we don't have the src user's
* password so we cannot generate a new file with a new salt.
*/
int in = TEMP_FAILURE_RETRY(open((*src)->getMasterKeyFileName().c_str(), O_RDONLY));
if (in < 0) {
return ResponseCode::SYSTEM_ERROR;
}
blobv3 rawBlob;
size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
if (close(in) != 0) {
return ResponseCode::SYSTEM_ERROR;
}
int out = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(),
O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
if (out < 0) {
return ResponseCode::SYSTEM_ERROR;
}
size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
if (close(out) != 0) {
return ResponseCode::SYSTEM_ERROR;
}
if (outLength != length) {
ALOGW("blob not fully written %zu != %zu", outLength, length);
unlink(mMasterKeyEntry.getKeyBlobPath().c_str());
return ResponseCode::SYSTEM_ERROR;
}
return ResponseCode::NO_ERROR;
}
ResponseCode UserState::writeMasterKey(const android::String8& pw) {
std::vector<uint8_t> passwordKey(mMasterKey.size());
generateKeyFromPassword(passwordKey, pw, mSalt);
auto blobType = TYPE_MASTER_KEY_AES256;
if (mMasterKey.size() == kAes128KeySizeBytes) {
blobType = TYPE_MASTER_KEY;
}
Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt), blobType);
auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR);
}
ResponseCode UserState::readMasterKey(const android::String8& pw) {
auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
int in = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(), O_RDONLY));
if (in < 0) {
return ResponseCode::SYSTEM_ERROR;
}
// We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
// to use with decryptBlob
blobv3 rawBlob;
size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
if (close(in) != 0) {
return ResponseCode::SYSTEM_ERROR;
}
// find salt at EOF if present, otherwise we have an old file
uint8_t* salt;
if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
} else {
salt = nullptr;
}
size_t masterKeySize = MASTER_KEY_SIZE_BYTES;
if (rawBlob.type == TYPE_MASTER_KEY) {
masterKeySize = kAes128KeySizeBytes;
}
std::vector<uint8_t> passwordKey(masterKeySize);
generateKeyFromPassword(passwordKey, pw, salt);
Blob masterKeyBlob, dummyBlob;
ResponseCode response;
std::tie(response, masterKeyBlob, dummyBlob) =
lockedEntry.readBlobs(passwordKey, STATE_NO_ERROR);
if (response == ResponseCode::SYSTEM_ERROR) {
return response;
}
size_t masterKeyBlobLength = static_cast<size_t>(masterKeyBlob.getLength());
if (response == ResponseCode::NO_ERROR && masterKeyBlobLength == masterKeySize) {
// If salt was missing, generate one and write a new master key file with the salt.
if (salt == nullptr) {
if (!generateSalt()) {
return ResponseCode::SYSTEM_ERROR;
}
response = writeMasterKey(pw);
}
if (response == ResponseCode::NO_ERROR) {
mMasterKey = std::vector<uint8_t>(masterKeyBlob.getValue(),
masterKeyBlob.getValue() + masterKeyBlob.getLength());
setupMasterKeys();
}
return response;
}
LOG(ERROR) << "Invalid password presented";
return ResponseCode::WRONG_PASSWORD_0;
}
bool UserState::reset() {
DIR* dir = opendir(mMasterKeyEntry.user_dir().c_str());
if (!dir) {
// If the directory doesn't exist then nothing to do.
if (errno == ENOENT) {
return true;
}
ALOGW("couldn't open user directory: %s", strerror(errno));
return false;
}
struct dirent* file;
while ((file = readdir(dir)) != nullptr) {
// skip . and ..
if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
continue;
}
unlinkat(dirfd(dir), file->d_name, 0);
}
closedir(dir);
return true;
}
void UserState::generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
uint8_t* salt) {
size_t saltSize;
if (salt != nullptr) {
saltSize = SALT_SIZE;
} else {
// Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
salt = (uint8_t*)"keystore";
// sizeof = 9, not strlen = 8
saltSize = sizeof("keystore");
}
const EVP_MD* digest = EVP_sha256();
// SHA1 was used prior to increasing the key size
if (key.size() == kAes128KeySizeBytes) {
digest = EVP_sha1();
}
PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(pw.string()), pw.length(), salt, saltSize, 8192,
digest, key.size(), key.data());
}
bool UserState::generateSalt() {
return RAND_bytes(mSalt, sizeof(mSalt));
}
bool UserState::generateMasterKey() {
mMasterKey.resize(MASTER_KEY_SIZE_BYTES);
if (!RAND_bytes(mMasterKey.data(), mMasterKey.size())) {
return false;
}
if (!generateSalt()) {
return false;
}
return true;
}
void UserState::setupMasterKeys() {
setState(STATE_NO_ERROR);
}
LockedUserState<UserState> UserStateDB::getUserState(uid_t userId) {
std::unique_lock<std::mutex> lock(locked_state_mutex_);
decltype(mMasterKeys.begin()) it;
bool inserted;
std::tie(it, inserted) = mMasterKeys.emplace(userId, userId);
if (inserted) {
if (!it->second.initialize()) {
/* There's not much we can do if initialization fails. Trying to
* unlock the keystore for that user will fail as well, so any
* subsequent request for this user will just return SYSTEM_ERROR.
*/
ALOGE("User initialization failed for %u; subsequent operations will fail", userId);
}
}
return get(std::move(lock), &it->second);
}
LockedUserState<UserState> UserStateDB::getUserStateByUid(uid_t uid) {
return getUserState(get_user_id(uid));
}
LockedUserState<const UserState> UserStateDB::getUserState(uid_t userId) const {
std::unique_lock<std::mutex> lock(locked_state_mutex_);
auto it = mMasterKeys.find(userId);
if (it == mMasterKeys.end()) return {};
return get(std::move(lock), &it->second);
}
LockedUserState<const UserState> UserStateDB::getUserStateByUid(uid_t uid) const {
return getUserState(get_user_id(uid));
}
} // namespace keystore

View file

@ -1,131 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef KEYSTORE_USER_STATE_H_
#define KEYSTORE_USER_STATE_H_
#include <sys/types.h>
#include <openssl/aes.h>
#include <utils/String8.h>
#include <keystore/keystore.h>
#include "blob.h"
#include "keystore_utils.h"
#include <android-base/logging.h>
#include <condition_variable>
#include <keystore/keystore_concurrency.h>
#include <mutex>
#include <set>
#include <vector>
namespace keystore {
class UserState;
template <typename UserState> using LockedUserState = ProxyLock<UnlockProxyLockHelper<UserState>>;
class UserState {
public:
explicit UserState(uid_t userId);
bool initialize();
uid_t getUserId() const { return mUserId; }
const std::string& getUserDirName() const { return mMasterKeyEntry.user_dir(); }
std::string getMasterKeyFileName() const { return mMasterKeyEntry.getKeyBlobPath(); }
void setState(State state);
State getState() const { return mState; }
void zeroizeMasterKeysInMemory();
bool deleteMasterKey();
ResponseCode initialize(const android::String8& pw);
ResponseCode copyMasterKey(LockedUserState<UserState>* src);
ResponseCode copyMasterKeyFile(LockedUserState<UserState>* src);
ResponseCode writeMasterKey(const android::String8& pw);
ResponseCode readMasterKey(const android::String8& pw);
const std::vector<uint8_t>& getEncryptionKey() const { return mMasterKey; }
bool reset();
bool operator<(const UserState& rhs) const;
bool operator<(uid_t userId) const;
private:
static constexpr int SHA1_DIGEST_SIZE_BYTES = 16;
static constexpr int SHA256_DIGEST_SIZE_BYTES = 32;
static constexpr int MASTER_KEY_SIZE_BYTES = kAes256KeySizeBytes;
static constexpr int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
static constexpr size_t SALT_SIZE = 16;
void generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
uint8_t* salt);
bool generateSalt();
bool generateMasterKey();
void setupMasterKeys();
KeyBlobEntry mMasterKeyEntry;
uid_t mUserId;
State mState;
std::vector<uint8_t> mMasterKey;
uint8_t mSalt[SALT_SIZE];
};
bool operator<(uid_t userId, const UserState& rhs);
class UserStateDB {
public:
LockedUserState<UserState> getUserState(uid_t userId);
LockedUserState<UserState> getUserStateByUid(uid_t uid);
LockedUserState<const UserState> getUserState(uid_t userId) const;
LockedUserState<const UserState> getUserStateByUid(uid_t uid) const;
private:
mutable std::set<const UserState*> locked_state_;
mutable std::mutex locked_state_mutex_;
mutable std::condition_variable locked_state_mutex_cond_var_;
template <typename UserState>
LockedUserState<UserState> get(std::unique_lock<std::mutex> lock, UserState* entry) const {
locked_state_mutex_cond_var_.wait(
lock, [&] { return locked_state_.find(entry) == locked_state_.end(); });
locked_state_.insert(entry);
return {entry, [&](UserState* entry) {
std::unique_lock<std::mutex> lock(locked_state_mutex_);
locked_state_.erase(entry);
lock.unlock();
locked_state_mutex_cond_var_.notify_all();
}};
}
std::map<uid_t, UserState> mMasterKeys;
};
} // namespace keystore
#endif // KEYSTORE_USER_STATE_H_