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:
commit
545463ccbb
29 changed files with 0 additions and 3826 deletions
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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();
|
||||
}
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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_
|
Loading…
Reference in a new issue