summaryrefslogtreecommitdiff
authorXindong Xu <xindong.xu@amlogic.com>2020-04-27 01:42:41 (GMT)
committer Xindong Xu <xindong.xu@amlogic.com>2020-04-27 01:42:41 (GMT)
commit5f98c979d780115f85f8c815e57a620b73471bfc (patch)
treef5a1bed37f9244a934625bdae5c7d8246b0d7aab
parentee9f363f98df4f99de4efcec553f97ae654e474c (diff)
downloadkeymaster-5f98c979d780115f85f8c815e57a620b73471bfc.zip
keymaster-5f98c979d780115f85f8c815e57a620b73471bfc.tar.gz
keymaster-5f98c979d780115f85f8c815e57a620b73471bfc.tar.bz2
keymaster: sync to ref q
2e847b99eabc67bc7ba1fccb77d7aa3399eb7d75 Change-Id: I37fbba12c99ce802dd1f636d1b69922ab037875e
Diffstat
-rwxr-xr-x4.0/AmlogicKeymaster4Device.cpp571
-rwxr-xr-x4.0/android.hardware.keymaster@4.0-service.amlogic.rc4
-rwxr-xr-x4.0/service.cpp43
-rwxr-xr-x[-rw-r--r--]8efb1e1c-37e5-4326-a5d68c33726c7d57.ta11646
-rwxr-xr-xAmlogicKeymaster.cpp352
-rwxr-xr-x[-rw-r--r--]Android.mk125
-rw-r--r--aml_keymaster_device.cpp1021
-rw-r--r--aml_keymaster_device.h194
-rw-r--r--aml_keymaster_ipc.cpp128
-rw-r--r--aml_keymaster_ipc.h33
-rwxr-xr-xinclude/amlogic_keymaster/AmlogicKeymaster.h86
-rwxr-xr-xinclude/amlogic_keymaster/AmlogicKeymaster4Device.h105
-rwxr-xr-xinclude/amlogic_keymaster/amlogic_keymaster_messages.h222
-rwxr-xr-xinclude/amlogic_keymaster/ipc/amlogic_keymaster_ipc.h52
-rwxr-xr-x[-rw-r--r--]include/amlogic_keymaster/ipc/keymaster_ipc.h (renamed from keymaster_ipc.h)17
-rwxr-xr-xipc/amlogic_keymaster_ipc.cpp325
-rw-r--r--module.cpp61
-rw-r--r--unit_test/android_keymaster_messages_test.cpp732
-rw-r--r--unit_test/android_keymaster_test.cpp3976
-rw-r--r--unit_test/android_keymaster_test_utils.cpp902
-rw-r--r--unit_test/android_keymaster_test_utils.h470
-rw-r--r--unit_test/android_keymaster_utils.h306
-rw-r--r--unit_test/attestation_record.cpp690
-rw-r--r--unit_test/attestation_record.h62
-rw-r--r--unit_test/attestation_record_test.cpp145
-rw-r--r--unit_test/authorization_set_test.cpp745
-rw-r--r--unit_test/ecies_kem_test.cpp73
-rw-r--r--unit_test/gtest_main.cpp34
-rw-r--r--unit_test/hkdf_test.cpp78
-rw-r--r--unit_test/hmac_test.cpp84
-rw-r--r--unit_test/kdf1_test.cpp60
-rw-r--r--unit_test/kdf2_test.cpp86
-rw-r--r--unit_test/kdf_test.cpp46
-rw-r--r--unit_test/key_blob_test.cpp362
-rw-r--r--unit_test/keymaster0_engine.h103
-rw-r--r--unit_test/keymaster1_engine.h123
-rw-r--r--unit_test/keymaster_configuration_test.cpp68
-rw-r--r--unit_test/keymaster_enforcement_test.cpp872
-rw-r--r--unit_test/keymaster_tags.cpp173
-rw-r--r--unit_test/nist_curve_key_exchange_test.cpp219
-rw-r--r--unit_test/openssl_utils.h100
-rw-r--r--unit_test/sw_rsa_attest_root.key.pem15
42 files changed, 6493 insertions, 19016 deletions
diff --git a/4.0/AmlogicKeymaster4Device.cpp b/4.0/AmlogicKeymaster4Device.cpp
new file mode 100755
index 0000000..2cf5fb2
--- a/dev/null
+++ b/4.0/AmlogicKeymaster4Device.cpp
@@ -0,0 +1,571 @@
+/*
+ **
+ ** 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.
+ */
+
+#define LOG_TAG "android.hardware.keymaster@4.0-impl.amlogic"
+
+#include <authorization_set.h>
+#include <log/log.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <amlogic_keymaster/AmlogicKeymaster4Device.h>
+#include <amlogic_keymaster/ipc/amlogic_keymaster_ipc.h>
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::AddEntropyRequest;
+using ::keymaster::AddEntropyResponse;
+using ::keymaster::AttestKeyRequest;
+using ::keymaster::AttestKeyResponse;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::BeginOperationRequest;
+using ::keymaster::BeginOperationResponse;
+using ::keymaster::ExportKeyRequest;
+using ::keymaster::ExportKeyResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::GenerateKeyRequest;
+using ::keymaster::GenerateKeyResponse;
+using ::keymaster::GetKeyCharacteristicsRequest;
+using ::keymaster::GetKeyCharacteristicsResponse;
+using ::keymaster::ImportKeyRequest;
+using ::keymaster::ImportKeyResponse;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using ::keymaster::ng::Tag;
+
+namespace keymaster {
+namespace V4_0 {
+namespace {
+
+inline keymaster_tag_t legacy_enum_conversion(const Tag value) {
+ return keymaster_tag_t(value);
+}
+inline Tag legacy_enum_conversion(const keymaster_tag_t value) {
+ return Tag(value);
+}
+inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+ return keymaster_purpose_t(value);
+}
+inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+ return keymaster_key_format_t(value);
+}
+
+inline SecurityLevel legacy_enum_conversion(const keymaster_security_level_t value) {
+ return static_cast<SecurityLevel>(value);
+}
+
+inline hw_authenticator_type_t legacy_enum_conversion(const HardwareAuthenticatorType value) {
+ return static_cast<hw_authenticator_type_t>(value);
+}
+
+inline ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+ return ErrorCode(value);
+}
+
+inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+ return keymaster_tag_get_type(tag);
+}
+
+class KmParamSet : public keymaster_key_param_set_t {
+ public:
+ KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+ params = new keymaster_key_param_t[keyParams.size()];
+ length = keyParams.size();
+ for (size_t i = 0; i < keyParams.size(); ++i) {
+ auto tag = legacy_enum_conversion(keyParams[i].tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+ break;
+ case KM_DATE:
+ params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+ break;
+ case KM_BOOL:
+ if (keyParams[i].f.boolValue)
+ params[i] = keymaster_param_bool(tag);
+ else
+ params[i].tag = KM_TAG_INVALID;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ params[i] = keymaster_param_blob(tag, &keyParams[i].blob[0],
+ keyParams[i].blob.size());
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ }
+ KmParamSet(KmParamSet&& other) noexcept
+ : keymaster_key_param_set_t{other.params, other.length} {
+ other.length = 0;
+ other.params = nullptr;
+ }
+ KmParamSet(const KmParamSet&) = delete;
+ ~KmParamSet() { delete[] params; }
+};
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
+ return result;
+}
+
+inline hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
+ return result;
+}
+
+inline hidl_vec<uint8_t> kmBuffer2hidlVec(const ::keymaster::Buffer& buf) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(buf.peek_read()), buf.available_read());
+ return result;
+}
+
+inline static hidl_vec<hidl_vec<uint8_t>> kmCertChain2Hidl(
+ const keymaster_cert_chain_t& cert_chain) {
+ hidl_vec<hidl_vec<uint8_t>> result;
+ if (!cert_chain.entry_count || !cert_chain.entries) return result;
+
+ result.resize(cert_chain.entry_count);
+ for (size_t i = 0; i < cert_chain.entry_count; ++i) {
+ result[i] = kmBlob2hidlVec(cert_chain.entries[i]);
+ }
+
+ return result;
+}
+
+static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
+ hidl_vec<KeyParameter> result;
+ if (set.length == 0 || set.params == nullptr) return result;
+
+ result.resize(set.length);
+ keymaster_key_param_t* params = set.params;
+ for (size_t i = 0; i < set.length; ++i) {
+ auto tag = params[i].tag;
+ result[i].tag = legacy_enum_conversion(tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ result[i].f.integer = params[i].enumerated;
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ result[i].f.integer = params[i].integer;
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ result[i].f.longInteger = params[i].long_integer;
+ break;
+ case KM_DATE:
+ result[i].f.dateTime = params[i].date_time;
+ break;
+ case KM_BOOL:
+ result[i].f.boolValue = params[i].boolean;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
+ params[i].blob.data_length);
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ return result;
+}
+
+void addClientAndAppData(const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ ::keymaster::AuthorizationSet* params) {
+ params->Clear();
+ if (clientId.size()) {
+ params->push_back(::keymaster::TAG_APPLICATION_ID, clientId.data(), clientId.size());
+ }
+ if (appData.size()) {
+ params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
+ }
+}
+
+} // anonymous namespace
+
+AmlogicKeymaster4Device::AmlogicKeymaster4Device(AmlogicKeymaster* impl) : impl_(impl) {}
+
+AmlogicKeymaster4Device::~AmlogicKeymaster4Device() {}
+
+Return<void> AmlogicKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_cb) {
+ _hidl_cb(SecurityLevel::TRUSTED_ENVIRONMENT, "AmlogicKeymaster", "Google");
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::getHmacSharingParameters(
+ getHmacSharingParameters_cb _hidl_cb) {
+ const GetHmacSharingParametersResponse response = impl_->GetHmacSharingParameters();
+ // response.params is not the same as the HIDL structure, we need to convert it
+ V4_0::HmacSharingParameters params;
+ params.seed.setToExternal(const_cast<uint8_t*>(response.params.seed.data),
+ response.params.seed.data_length);
+ static_assert(sizeof(response.params.nonce) == params.nonce.size(), "Nonce sizes don't match");
+ memcpy(params.nonce.data(), response.params.nonce, params.nonce.size());
+ _hidl_cb(legacy_enum_conversion(response.error), params);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::computeSharedHmac(
+ const hidl_vec<HmacSharingParameters>& params, computeSharedHmac_cb _hidl_cb) {
+ ComputeSharedHmacRequest request;
+ request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
+ request.params_array.num_params = params.size();
+ for (size_t i = 0; i < params.size(); ++i) {
+ request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()};
+ static_assert(sizeof(request.params_array.params_array[i].nonce) ==
+ decltype(params[i].nonce)::size(),
+ "Nonce sizes don't match");
+ memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+ params[i].nonce.size());
+ }
+
+ auto response = impl_->ComputeSharedHmac(request);
+ hidl_vec<uint8_t> sharing_check;
+ if (response.error == KM_ERROR_OK) {
+ sharing_check = kmBlob2hidlVec(response.sharing_check);
+ }
+
+ _hidl_cb(legacy_enum_conversion(response.error), sharing_check);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::verifyAuthorization(
+ uint64_t challenge, const hidl_vec<KeyParameter>& parametersToVerify,
+ const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) {
+ VerifyAuthorizationRequest request;
+ request.challenge = challenge;
+ request.parameters_to_verify.Reinitialize(KmParamSet(parametersToVerify));
+ request.auth_token.challenge = authToken.challenge;
+ request.auth_token.user_id = authToken.userId;
+ request.auth_token.authenticator_id = authToken.authenticatorId;
+ request.auth_token.authenticator_type = legacy_enum_conversion(authToken.authenticatorType);
+ request.auth_token.timestamp = authToken.timestamp;
+ KeymasterBlob mac(authToken.mac.data(), authToken.mac.size());
+ request.auth_token.mac = mac;
+
+ auto response = impl_->VerifyAuthorization(request);
+
+ ::android::hardware::keymaster::V4_0::VerificationToken token;
+ token.challenge = response.token.challenge;
+ token.timestamp = response.token.timestamp;
+ token.parametersVerified = kmParamSet2Hidl(response.token.parameters_verified);
+ token.securityLevel = legacy_enum_conversion(response.token.security_level);
+ token.mac = kmBlob2hidlVec(response.token.mac);
+
+ _hidl_cb(legacy_enum_conversion(response.error), token);
+
+ return Void();
+}
+
+Return<ErrorCode> AmlogicKeymaster4Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
+ if (data.size() == 0) return ErrorCode::OK;
+ AddEntropyRequest request;
+ request.random_data.Reinitialize(data.data(), data.size());
+
+ AddEntropyResponse response;
+ impl_->AddRngEntropy(request, &response);
+
+ return legacy_enum_conversion(response.error);
+}
+
+Return<void> AmlogicKeymaster4Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) {
+ GenerateKeyRequest request;
+ request.key_description.Reinitialize(KmParamSet(keyParams));
+
+ GenerateKeyResponse response;
+ impl_->GenerateKey(request, &response);
+
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+ if (response.error == KM_ERROR_OK) {
+ resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+ resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) {
+ GetKeyCharacteristicsRequest request;
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+ addClientAndAppData(clientId, appData, &request.additional_params);
+
+ GetKeyCharacteristicsResponse response;
+ impl_->GetKeyCharacteristics(request, &response);
+
+ KeyCharacteristics resultCharacteristics;
+ if (response.error == KM_ERROR_OK) {
+ resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultCharacteristics);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::importKey(const hidl_vec<KeyParameter>& params,
+ KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData,
+ importKey_cb _hidl_cb) {
+ ImportKeyRequest request;
+ request.key_description.Reinitialize(KmParamSet(params));
+ request.key_format = legacy_enum_conversion(keyFormat);
+ request.SetKeyMaterial(keyData.data(), keyData.size());
+
+ ImportKeyResponse response;
+ impl_->ImportKey(request, &response);
+
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+ if (response.error == KM_ERROR_OK) {
+ resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+ resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::importWrappedKey(
+ const hidl_vec<uint8_t>& wrappedKeyData, const hidl_vec<uint8_t>& wrappingKeyBlob,
+ const hidl_vec<uint8_t>& maskingKey, const hidl_vec<KeyParameter>& unwrappingParams,
+ uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) {
+ ImportWrappedKeyRequest request;
+ request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+ request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+ request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+ request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+ request.password_sid = passwordSid;
+ request.biometric_sid = biometricSid;
+
+ ImportWrappedKeyResponse response;
+ impl_->ImportWrappedKey(request, &response);
+
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+ if (response.error == KM_ERROR_OK) {
+ resultKeyBlob = kmBlob2hidlVec(response.key_blob);
+ resultCharacteristics.hardwareEnforced = kmParamSet2Hidl(response.enforced);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(response.unenforced);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob, resultCharacteristics);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::exportKey(KeyFormat exportFormat,
+ const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) {
+ ExportKeyRequest request;
+ request.key_format = legacy_enum_conversion(exportFormat);
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+ addClientAndAppData(clientId, appData, &request.additional_params);
+
+ ExportKeyResponse response;
+ impl_->ExportKey(request, &response);
+
+ hidl_vec<uint8_t> resultKeyBlob;
+ if (response.error == KM_ERROR_OK) {
+ resultKeyBlob.setToExternal(response.key_data, response.key_data_length);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) {
+ AttestKeyRequest request;
+ request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
+ request.attest_params.Reinitialize(KmParamSet(attestParams));
+
+ AttestKeyResponse response;
+ impl_->AttestKey(request, &response);
+
+ hidl_vec<hidl_vec<uint8_t>> resultCertChain;
+ if (response.error == KM_ERROR_OK) {
+ resultCertChain = kmCertChain2Hidl(response.certificate_chain);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultCertChain);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) {
+ UpgradeKeyRequest request;
+ request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+ request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+ UpgradeKeyResponse response;
+ impl_->UpgradeKey(request, &response);
+
+ if (response.error == KM_ERROR_OK) {
+ _hidl_cb(ErrorCode::OK, kmBlob2hidlVec(response.upgraded_key));
+ } else {
+ _hidl_cb(legacy_enum_conversion(response.error), hidl_vec<uint8_t>());
+ }
+ return Void();
+}
+
+Return<ErrorCode> AmlogicKeymaster4Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+ DeleteKeyRequest request;
+ request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+ DeleteKeyResponse response;
+ impl_->DeleteKey(request, &response);
+
+ return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> AmlogicKeymaster4Device::deleteAllKeys() {
+ DeleteAllKeysRequest request;
+ DeleteAllKeysResponse response;
+ impl_->DeleteAllKeys(request, &response);
+
+ return legacy_enum_conversion(response.error);
+}
+
+Return<ErrorCode> AmlogicKeymaster4Device::destroyAttestationIds() {
+ return ErrorCode::UNIMPLEMENTED;
+}
+
+Return<void> AmlogicKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams,
+ const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+ (void)authToken;
+ BeginOperationRequest request;
+ request.purpose = legacy_enum_conversion(purpose);
+ request.SetKeyMaterial(key.data(), key.size());
+ request.additional_params.Reinitialize(KmParamSet(inParams));
+
+ BeginOperationResponse response;
+ impl_->BeginOperation(request, &response);
+
+ hidl_vec<KeyParameter> resultParams;
+ if (response.error == KM_ERROR_OK) {
+ resultParams = kmParamSet2Hidl(response.output_params);
+ }
+
+ _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::update(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken,
+ update_cb _hidl_cb) {
+ (void)authToken;
+ (void)verificationToken;
+ UpdateOperationRequest request;
+ UpdateOperationResponse response;
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+ uint32_t resultConsumed = 0;
+
+ request.op_handle = operationHandle;
+ request.additional_params.Reinitialize(KmParamSet(inParams));
+
+ size_t inp_size = input.size();
+ size_t ser_size = request.SerializedSize();
+
+ if (ser_size > AMLOGIC_KEYMASTER_SEND_BUF_SIZE) {
+ response.error = KM_ERROR_INVALID_INPUT_LENGTH;
+ } else {
+ if (ser_size + inp_size > AMLOGIC_KEYMASTER_SEND_BUF_SIZE) {
+ inp_size = AMLOGIC_KEYMASTER_SEND_BUF_SIZE - ser_size;
+ }
+ request.input.Reinitialize(input.data(), inp_size);
+
+ impl_->UpdateOperation(request, &response);
+
+ if (response.error == KM_ERROR_OK) {
+ resultConsumed = response.input_consumed;
+ resultParams = kmParamSet2Hidl(response.output_params);
+ resultBlob = kmBuffer2hidlVec(response.output);
+ }
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultConsumed, resultParams, resultBlob);
+ return Void();
+}
+
+Return<void> AmlogicKeymaster4Device::finish(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken,
+ finish_cb _hidl_cb) {
+ (void)authToken;
+ (void)verificationToken;
+ FinishOperationRequest request;
+ request.op_handle = operationHandle;
+ request.input.Reinitialize(input.data(), input.size());
+ request.signature.Reinitialize(signature.data(), signature.size());
+ request.additional_params.Reinitialize(KmParamSet(inParams));
+
+ FinishOperationResponse response;
+ impl_->FinishOperation(request, &response);
+
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+ if (response.error == KM_ERROR_OK) {
+ resultParams = kmParamSet2Hidl(response.output_params);
+ resultBlob = kmBuffer2hidlVec(response.output);
+ }
+ _hidl_cb(legacy_enum_conversion(response.error), resultParams, resultBlob);
+ return Void();
+}
+
+Return<ErrorCode> AmlogicKeymaster4Device::abort(uint64_t operationHandle) {
+ AbortOperationRequest request;
+ request.op_handle = operationHandle;
+
+ AbortOperationResponse response;
+ impl_->AbortOperation(request, &response);
+
+ return legacy_enum_conversion(response.error);
+}
+} // namespace V4_0
+} // namespace keymaster
diff --git a/4.0/android.hardware.keymaster@4.0-service.amlogic.rc b/4.0/android.hardware.keymaster@4.0-service.amlogic.rc
new file mode 100755
index 0000000..53b1651
--- a/dev/null
+++ b/4.0/android.hardware.keymaster@4.0-service.amlogic.rc
@@ -0,0 +1,4 @@
+service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service.amlogic
+ class early_hal
+ user system
+ group system drmrpc
diff --git a/4.0/service.cpp b/4.0/service.cpp
new file mode 100755
index 0000000..6a7105a
--- a/dev/null
+++ b/4.0/service.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** 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.
+*/
+
+#include <android-base/logging.h>
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <hidl/HidlTransportSupport.h>
+#include <amlogic_keymaster/AmlogicKeymaster.h>
+#include <amlogic_keymaster/AmlogicKeymaster4Device.h>
+
+int main() {
+ ::android::hardware::configureRpcThreadpool(1, true);
+ auto trustyKeymaster = new keymaster::AmlogicKeymaster();
+ int err = trustyKeymaster->Initialize();
+ if (err != 0) {
+ LOG(FATAL) << "Could not initialize AmlogicKeymaster (" << err << ")";
+ return -1;
+ }
+
+ auto keymaster = new ::keymaster::V4_0::AmlogicKeymaster4Device(trustyKeymaster);
+
+ auto status = keymaster->registerAsService();
+ if (status != android::OK) {
+ LOG(FATAL) << "Could not register service for Keymaster 4.0 (" << status << ")";
+ return -1;
+ }
+
+ android::hardware::joinRpcThreadpool();
+ return -1; // Should never get here.
+}
diff --git a/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta b/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta
index 4f50e04..97a792b 100644..100755
--- a/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta
+++ b/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta
@@ -1,2867 +1,2758 @@
-HSTO
-
-
-
-
-ÿv¡Áïöe ÿtÁÿvÿÿÔ@ÿÿÐ`DÿÖAFÿÒaDïðAFïðaÿtaÁïôEÿv!ÁïöeÿtA
-ÿt¡ÿvþÿÒ@þÿÐ`DÿÖAFÿÔaDïòAFïòaÿtaÂïôEÿvAÂïöeÿt!
-ÿt¡ÄïôEÿvÄïöeÿt!
-ÿP¡ÿV!FÿPaNÿXABÿ\!HÿP¡dïôJÿTdïòAFÿðáFïøÁfïøaHÿò@ïòLÿT!NïøáJïò¡Fÿ^!BÿZFÿúaDÿúABïø¡bïø!Fÿþa@ÿúDÿüABÿþ!@ÿüHï\Bÿü!@ïT¡NïRÁfïZáFÿøaBÿü!@ÿþDÿúAFïòÁ`ïðDÿü¡@ÿüá@ÿüÁRÿð¡VÿôáFÿôaZÿü\ÿúHïþÁBÿð!LÿöÁJÿTBÿ\NÿüADïÚA
-ÿR¡Bï~a
-ï|¡ÿô!
-ÿv¡NÿúáLÿòÁNÿüaJÿòAFïøaDïÔAHÿðÿ\A@ïþ ïzÁHïüïrA@ÿøÿ\AHÿö ÿtÁ
-ÿx¡ÿxAÿp! ÿpÁFÿPNÿXNÿüaJÿòAFïøaDïÐAHÿð
-ÿ^¡ÿTÿPáÿZÿ\a ÿRÁÿXaÿPÿVá=Àð€ðï@öïFÈúïJè@ÿÐòïB(LÿÖÁüïLHNÿÚáøïHhBÿÒ!ôïDˆDÿÜAþïN¨FÿØaHÿÔJÿÞ¡
-ÿz¡ðï@ òïB,
-ÿ~¡°ï@DÿÒA@ÿÚBÿÚ!²ïB(JÿÔ¡
-ÿt¡ÁïôEÿváÁïöeÿtaÿvAÿÿÜ@ÿÿÐ`DÿØAFÿÒaDïðAFïðaÿtÁïôEÿv!Áïöe ÿtÁ
-ÿt¡ÂïôEÿvaÂïöeÿtáÿvAþÿÒ@þÿÐ`DÿØAFÿÜaDïòAFïòaÿtÂïôE ÿvÁÂïöeÿt!
-ÿt¡ÄïôEÿvaÄïöeÿt ÿvÁüÿÒ@üÿÐ`DÿÞAFÿÔaDïðAFïðaÿtáÄïôEÿvAÄïöeÿt!
-ÿp¡
-  
-   
-
-  
- 
-
-  
- Bit-sliced AES for NEON, CRYPTOGAMS by <appro@openssl.org>
-ÿv¡Áïöe ÿtÁÿvÿÿÔ@ÿÿÐ`DÿÖAFÿÒaDïðAFïðaÿtaÁïôEÿv!ÁïöeÿtA
-ÿt¡ÿvþÿÒ@þÿÐ`DÿÖAFÿÔaDïòAFïòaÿtaÂïôEÿvAÂïöeÿt!
-ÿt¡ÄïôEÿvÄïöeÿt!
-ÿ\¡ÿPa ÿTÁ
-ÿP¡ ÿVÁÿ^aÿZáÿXaÿZÿ^AÿRaÿZ!NÿXaBÿTAJÿV!DÿX¡dïôLÿPdïòAFÿðáFïøÁfïøaHÿò@ïòFÿP!NïøáJïò¡NÿR!Jÿ\FÿúaDÿúABïø¡bïø!Fÿþa@ÿúDÿüABÿþ!@ÿüDïVBÿü!HïP¡BïZÁnï\áFÿøaBÿü!@ÿþDÿúAFïòÁ`ïðDÿü¡@ÿüá@ÿüÁRÿð¡VÿôáFÿôaZÿü\ÿúHïþÁBÿð!LÿöÁLÿPJÿVNÿüADïÜA ÿZÁJï~a ï|Áÿô¡ ÿvÁNÿúáLÿòÁNÿüaJÿòAFïøaDïÐAHÿð
-ÿp¡ÿpaNÿXBÿTNÿüaJÿòAFïøaDïØAHÿðÿT@ïþïzAHïüïr@ÿøÿTHÿöÿtANÿúáLÿòÁNÿüADïÞAÿRáBï~aï|áÿô!ÿváÿxáÿxÿp!ÿpAÿPáÿ\! ÿPÁÿ^
-ÿT¡ÿVAÿZaÿZ ÿVÁ=_Óðï@ òïB,
-ÿ~¡°ï@DÿÒA@ÿÚBÿÚ!²ïB(JÿÖ¡
-ÿt¡ÁïôEÿváÁïöeÿtAÿvaÿÿØ@ÿÿÐ`DÿÜAFÿÒaDïðAFïða ÿtÁÁïôEÿv!Áïöeÿt
-ÿt¡ÂïôEÿvAÂïöeÿtáÿvaþÿÒ@þÿÐ`DÿÜAFÿØaDïòAFïòa ÿtÁÂïôEÿvÂïöeÿt!
-ÿt¡ÄïôEÿvAÄïöe ÿtÁÿvüÿÒ@üÿÐ`DÿÞAFÿÖaDïðAFïðaÿtáÄïôEÿvaÄïöeÿt!
-ÿp¡
-ÿ|¡ù Šù Jù êù jù ªÄç2
-*ÀðÝ€ ù *lFUFÉìë
-
-
-ù
-ەP
-ñì‹ÀïQ
-ÿ~¡ù ÊÀïQ
-
-**Ó`ù *ÿr!ù *#Ð`ù Jÿtù Š*Ó`ù j ÿvÁù ÊÐ`ù Šÿxaù j* Ó`ù ªÿzáù êÐ`ùÊÿ|Aù J€ïP
--ù*ñ˜úˆð
->ëÑ€ïP
-Ò¢¹ñ€ Àð¶€à
-²ÿ ÐïòàBÿÜ!ïZárïâH@ùí*²ÿðïôÀDÿÞA ïZÁ'ù
-tïäh@ùíJ²ÿ ÐïöàFÿÜaïZá'ù *
-'ù Â
-ÿz¡$¬ ÿ|Á Fÿ~áhFÿ÷Pù`ùí`ùíB
-¹ñ€ õR¯ñp
-²ÿðïòÀBÿÞ! ïZÁrïâH@ùí*²ÿ ÐïôàDÿÜAïZá'ù
-¹ñ
-ÿz¡$¬ ÿ|Á FhFÿ÷ø`ùí`ùíB
-Ðà¯ó
-ÿz¡ FhFÿ÷_ø`ùí`ùíB
-¦à¯ó
-pà¯ó
-Nà¯ó
-`ùï
-0à¯ó
-à¯ó
-RFF ðœÿ-ù/
-
-#Fbïòñ Шñø øø ø¹ñ ôØ&ù
-hF
-RFF ðwÿ-ù/
-
-#F#ð
-¯ò"ð¿©ñ ¹ñ€ Àð³€à¯ó
-²ÿ ÐïòàBÿÜ!ïZárïâH@ùí*²ÿðïôÀDÿÞA ïZÁ'ù
-tïäh@ùíJ²ÿ ÐïöàFÿÜaïZá'ù *
-'ù Â
-ÿz¡$¬ ÿ|Á Fÿ~áhFþ÷Àú`ùí`ùíB
-¹ñ€ õR¯ñp
-²ÿðïòÀBÿÞ! ïZÁrïâH@ùí*²ÿ ÐïôàDÿÜAïZá'ù
-¹ñ
-ÿz¡$¬ ÿ|Á FhFþ÷
-Ãà
-ÿz¡ FhFþ÷Íù`ùí`ùíB
-–à¯ó
-rà¯ó
-Pà¯ó
-`ùï
-2à¯ó
-à¯ó
-FRFF ð«ü-ù/
-
-#F*Fbïòñ ;Ð’ì«ïðÀ ïZÁpïà(²ÿ ÐBÿÜ!'ù
-hF
-RFF ð†ü-ù/
-
-FF˜ø
-hF
-RF ðiü-ù/
-
-#F#ð
- à
-ƒê ˜è
-‡ê Nø \˜è
-ƒê Nø ˜è
-‡ê NøKNø \(¿¨ñ@ NølNø|?öm®ÐÝø„À ñ
- ø»ôÑ#°½èðÝø
-nùŠ ùB ùÍøh Íøl°áï8¥Íí‹âï8ÅÍí« ïPÍíË`ïP"ïR¡bïR!à¯ó
- ñ à
-ÿz¡lù ‚ ÿ|Áù Bÿ~álù Â@ÿø+ùIÿ¹‘Ýí‹Bÿú!+ùBDÿüAù ‚Fÿþaù Â&ï(hÝí‹è
-Nø ƒê ˜è
-Nø \‡ê ˜è
-Nø ƒê ˜è
-NøK‡ê Nø \¨õ€{NølNø|?ö2­úà
- ÿ÷A»
-ùB´à¯ó
-ù«ñ@ ‘à
-ÿz¡ù  ÿ|Áù Bÿ~áù ‚ù ÂxÐ ñ Mù ñ
-HùB«ñ€ bà¯ó
-ÿz¡lù ‚ ÿ|Áù ÿ~álù Â@ÿøù BBÿú!ù ‚DÿüAù ÂFÿþaNù Nù B8Ðè
-«ñÀ ø‹ø›»ñ ˆê ø‹ôÑ$°ì‹°½èð¯ó
-µšš/ 6$›€€=ââß&ëëÍi''NͲ²Ÿuuê žƒƒt,,X.4-6²nnÜîZZ´û  [öRR¤M;;vaÖַγ³}{))R>ããÝq//^—„„õSS¦hÑѹ
+HSTO
+
+
+
+
+“Kl “‹k “ËkÑøÀÌh “ kÑø
+™W@ šy@Oê‘lÁó…z@ õÀ|Oê2Sø,À„ê Sø(@Œê Áó…$€4Áó…ASø$@õ€qSø!ŒêL@‘õàqSø!L@Âó…@1Sø!L@Âó…!À1Âó…BSø!õ rSø" L@™T@ ša@Oê‘lÁó…b@ õÀ|Oê2Sø,À‡ê Sø(pŒê Áó…'€7Áó…ASø'põ€qSø!ŒêO@‘õàqSø!O@Âó…@1Sø!O@Âó…!À1Âó…BSø!õ rSø" O@™W@šy@Oê‘lÁó…z@ õÀ|Oê2Sø,À„ê Sø(@Œê Áó…$€4Áó…ASø$@õ€qSø!ŒêL@‘õàqSø!L@Âó…@1Sø!L@Âó…!À1Âó…BSø!õ rSø" a@œQ@šL@Oê”lÄó…J@ õÀ|Oê2Sø,À‡ê Sø(pŒê Äó…'€7Äó…DSø'põ€tSø$@Œêg@”õàtSø$@|@Âó…@7Sø'p|@Âó…'À7Âó…BSø'põ rSø" |@ŸT@šg@‚ê Oê7OêœbÌó…õÀrSø" J@Sø(J@Ìó…!€1Ìó…LSø! õ€|J@Sø,J@¹õàqSø!J@Çó…@1Sø!J@Çó…!À1Çó…GSø!õ wJ@Sø'ŸJ@
+f@OêšbÊó…Oê6õÀrSø" Q@Sø% Q@Êó…"€2Êó…JSø"
+õ€zQ@Sø* Q@²õàrSø" Q@Æó…@2Sø" Q@Æó…"À2Æó…FSø" õ vSø&0Q@K@OêôOêó‚êSðU1ƒêAJ@ƒê$ðÿ‚ê"c@‚ê“ð31ƒêJ@ƒêA‰²‚êBK@‚êð1ƒêJ@`C`°½èðŠê
+ßøP7†êOêšfÊó… Oê2{DõÀvSø&`ˆêSø+`ˆêÊó…&€6Êó…JSø&`
+õ€zˆêSø*€†êOê’hõàxSø(€†êÂó…ñ@Sø(€†êÂó…(ñÀÂó…BSø(€õ rSø" †êr@ŽêU@OêžfÎó…Oê5õÀvSø&`w@Sø(`w@Îó…&€6Îó…NSø&`õ€~~@Sø.p~@¯õàwSø'p~@Åó…@7Sø'p~@Åó…'À7Åó…ESø'põ uSø%P~@
+V@ šu@Oê•nÅó…r@õÀ~Oê2Sø.à‡êSø(pŽêÅó…'€7Åó…ESø'põ€uSø%PŽêo@•õàuSø%Po@Âó…@5Sø%Po@Âó…%À5Âó…BSø%Põ rSø" o@ W@ š}@Oê•nÅó…z@õÀ~Oê2Sø.à†êSø(`ŽêÅó…&€6Åó…ESø&`õ€uSø%PŽên@•õàuSø%Pn@Âó…@5Sø%Pn@Âó…%À5Âó…BSø%Põ rSø" n@V@šu@Oê•nÅó…r@õÀ~Oê2Sø.à‡êSø(pŽêÅó…'€7Åó…ESø'põ€uSø%PŽêo@•õàuSø%Po@Âó…@5Sø%Po@Âó…%À5Âó…BSø%Põ rSø" o@W@šz@Oê’nÂó…}@õÀ~Oê5Sø.à†êSø(`ŽêÂó…&€6Âó…BSø&`õ€rSø" ŽêV@ªõàrSø" V@Åó…@2Sø" V@Åó…"À2Åó…ESø" õ uSø%Pr@žj@V@Oê–nÆó…U@õÀ~Oê5Sø.à‡êSø(pŽêÆó…'€7Æó…FSø'põ€vSø&`Žêw@®õàvSø&`~@Åó…@7Sø'p~@Åó…'À7Åó…ESø'põ uSø%P~@Ÿu@žo@†êOê7OêžfÎó…õÀvSø&`r@Sø(`V@Îó…"€2Sø" V@Îó…Bõ€rSø" V@ºõàrSø" V@Çó…@2Sø" V@Çó…"À2Çó…GSø" õ wV@Sø' ŸV@šw@Oê7‚êOêžbÎó…õÀrSø" j@Sø(Pj@Îó…%€5Sø%Pj@Îó…Eõ€uSø%Pj@½õàuSø%Pj@Çó…@5Sø%Pj@Çó…%À5Çó…GSø%Põ wj@Sø'Pj@Œê T@Oê4OêœdõÀtÌó…Sø$@t@Sø'`t@Ìó…&€6Ìó…LSø&` õ€|t@Sø,`t@®õàvSø&`t@Åó…@6Sø&`t@Åó…&À6Åó…ESø&`õ uSø%Pt@l@‰ê a@Oê™eÉó…Oê1õÀuSø%Pj@Sø&Pj@Éó…%€5Éó…ISø%P õ€yj@Sø)Pj@õàuSø%Pj@Áó…@5Sø%Pj@Áó…%À5Áó…ASø%Põ qSø!0j@S@+ä
+“Kl “‹k “ËkhÌh “ kÑø
+™W@ šy@Oê‘nÁó…z@õÀ~Oê2Sø.à„êSø(@ŽêÁó…$€4Áó…ASø$@õ€qSø!ŽêL@‘õàqSø!L@Âó…@1Sø!L@Âó…!À1Âó…BSø!õ rSø" L@™T@ ša@Oê‘nÁó…b@õÀ~Oê2Sø.à‡êSø(pŽêÁó…'€7Áó…ASø'põ€qSø!ŽêO@‘õàqSø!O@Âó…@1Sø!O@Âó…!À1Âó…BSø!õ rSø" O@™W@šy@Oê‘nÁó…z@õÀ~Oê2Sø.à„êSø(@ŽêÁó…$€4Áó…ASø$@õ€qSø!ŽêL@‘õàqSø!L@Âó…@1Sø!L@Âó…!À1Âó…BSø!õ rSø" a@œQ@šL@Oê”nÄó…J@õÀ~Oê2Sø.à‡êSø(pŽêÄó…'€7Äó…DSø'põ€tSø$@Žêg@”õàtSø$@|@Âó…@7Sø'p|@Âó…'À7Âó…BSø'põ rSø" |@ŸT@šg@‚êOê7OêžbÎó…õÀrSø" J@Sø(J@Îó…!€1Îó…NSø!õ€~J@Sø.J@¹õàqSø!J@Çó…@1Sø!J@Çó…!À1Çó…GSø!õ wJ@Sø'ŸJ@
+f@OêšbÊó…Oê6õÀrSø" Q@Sø% Q@Êó…"€2Êó…JSø"
+õ€zQ@Sø* Q@²õàrSø" Q@Æó…@2Sø" Q@Æó…"À2Æó…FSø" õ vSø&0Q@K@OêôOêó`C`°½èðŠê
+ßøÄ7†êOêšfÊó… Oê2{DõÀvSø&`ˆêSø+`ˆêÊó…&€6Êó…JSø&`
+õ€zˆêSø*€†êOê’hõàxSø(€†êÂó…ñ@Sø(€†êÂó…(ñÀÂó…BSø(€õ rSø" †êr@Œê U@OêœfÌó…Oê5õÀvSø&`ŽêSø(`ŽêÌó…&€6Ìó…LSø&` õ€|ŽêSø,àOê•l õà|†êSø,àÅó… ñ@ †êSø,àÅó…,Åó…E ñÀ õ uSø,À†êSø%P†ê n@
+V@ šu@Oê•nÅó…r@õÀ~Oê2Sø.àŒê Sø(àŒê Åó….ñ€Åó…ESø.€õ€uSø%PŒê Œê •õàuSø%PŒê Âó…@5Sø%PŒê Âó…%À5Âó…BSø%Põ rSø" Œê Œê š‚ê  šOê•nÅó…õÀ~‚ê Sø.àOê2†êSø(`ŽêÅó…&€6Åó…ESø&`õ€uSø%PŽên@•õàuSø%Pn@Âó…@5Sø%Pn@Âó…%À5Âó…BSø%Põ rSø" n@V@šu@Oê•nÅó…r@õÀ~Oê2Sø.àŒê Sø(àŒê Åó….ñ€Åó…ESø.€õ€uSø%PŒê Œê •õàuSø%PŒê Âó…@5Sø%PŒê Âó…%À5Âó…BSø%Põ rSø" Œê Œê š‚ê Oê’nÂó……ê õÀ~Oê5Sø.à†êSø(`ŽêÂó…&€6Âó…BSø&`õ€rSø" ŽêV@ªõàrSø" V@Åó…@2Sø" V@Åó…"À2Åó…ESø" õ uSø%Pr@žj@V@Oê–nÆó…U@õÀ~Oê5Sø.àŒê Sø(àŒê Æó….ñ€Æó…FSø.€õ€vSø&`Œê Œê ®õàvSø&`ŒêÅó… ñ@ Sø,À†ê Åó…, ñÀ Åó…ESø,Àõ uSø%P†ê u@ž†êžÎó…†ê OêžfOê<õÀvSø&`r@Sø(`V@Îó…"€2Sø" V@Îó…Bõ€rSø" V@OêœbõàrSø" V@Ìó…@2Sø" V@Ìó…"À2Ìó…LSø" õ |V@Sø, V@š‚êšÎó…‚ê OêžbOê<õÀrSø" j@Sø(Pj@Îó…%€5Sø%Pj@Îó…Eõ€uSø%Pj@OêœeõàuSø%Pj@Ìó…@5Sø%Pj@Ìó…%À5Ìó…LSø%P õ |j@Sø,Pj@W@T@Oê4¼õÀtÇó… Sø$@t@Sø,`t@Çó…&€6Çó…GSø&`õ€wt@Sø'`t@®õàvSø&`t@Åó…@6Sø&`t@Åó…&À6Åó…ESø&`õ uSø%Pt@l@‰ê a@Oê™eÉó…Oê1õÀuSø%Pj@Sø&Pj@Éó…%€5Éó…ISø%P õ€yj@Sø)Pj@õàuSø%Pj@Áó…@5Sø%Pj@Áó…%À5Áó…ASø%Põ qSø!0j@S@ärE
+Oð
+ˆi”iEñ
+ÐiEñ
+Añ
+cëñÿ6OêÑuCñÿ4vdëQOêÔ|Cñÿ0±ë ôF`ë
+“Kh “ hÑi‘‘i‘Qi‘i‘Ñh‘‘h‘Qhh‘’£ûÍé"š¢ûgš¢ûÍé š¢ûÍ隢û«š¢ûÍ隢ûÍ隢û4#š’%’ šÍé4Oð
+CëéCë ‘ëFCë
+BFCë
+Cë
+
+%—ë
+CëëHë
+Ýøˆ€$—ëÝø€€CëFë
+)FNë"—ëFCëëÝø¨àCë –FëCëÉ)ŸCë‘9FCë‰(žCë‘FFF‰CëI&Cë‘© Cë
+!FCë*Fë
+CëDCë Fë
+Ýø€Cëë°F*”]AÝøˆ FFë
+CëëÝø€€Fë"•ëCëëNë,Fë ”ëCë)•&Fœ4(”Cëœ Cë @'Ië ˜ACë ë &‘Lë ™ŠCëë $‘Gë
+šF%‘™F¢ûÍ陞 ûE™ û¦CëÍé™Ýøp° ûë CëëCëÍé™ û‰™ ûÍé™ ûÍé ™ ûÍé
+FÝøhÀÝøtà˜Ýøx°ëÝølÀCëëCëFë Ýø€ Cëë šCëëÝø(Cëí ŸCë8Cë@Bë šë CëR*™_Aë Ýøˆ°Cë ÈFë Cë ë"–Ië ëCëë Ýø¤Hë –ëCëëÝø €Fë”ë CëëÝøœàFë ”ëCëë ”F&˜Cë FCë€$žCëFF€FCë@ Bë +˜zOð
+Fë
+FFë
+Cë
+Cë
+
+*Cëë"•FÝøx€Fë
+™Š™Cë
+FÝø|ÀÝøp°Ÿë ˜Cëë Cëë žCëFÝø¨ ÷Cë?Cëë˜Cë¤Ýø0€Cëë ˜CëRCëFë
+™Cë’ë CëI^Aë
+CëÂFÝøˆ€ëCë ëæFÝø€ÀIë "’ë Cëë Ýø¤Hë ’ë CëëÝø €Në’ëœCë ë’Ië 'šÝø˜à¤FCë ë Lë ”ë
+”)‘Oðÿ1¥ûg,Fë
+8FCë1Fë
+CëeCë©Fë
+ÝøˆÝø€ Cëë ^A"•ëCë ­Ië •ë
+™Cë ë$‘Lë%‘˜™¡û
+™˜ž¡û
+Ýø`€ÍéFCë
+‘Nëë Ýø€°Cë "‘ÈFë Cë ë
+Ýøx Ië ‘ë FCëë ÝøpHë‘0Fë Cë ëÝø €Lë F‘ë
+›F ‘)™FãœBë
+“FëBë%˜Bë"œ
+CFBë
+Bë
+
+˜ÃBë ë$“Lë ›YBëë  “Gë™F"“›£û4™Íé4›£û‰™£û4™Íé4›£û4Íé 4›™Ýølà˜ž£û«™ëBë ë
+4›£û4™Íé4›£û4FBëë
+œë BëëBëöBëFë  ›BëäAë™ÝøÝø  [Ýøx°BëÙ›UAë Bë[WA“ë
+Ýøp Bë ÈFë Bë ëIë ë
+“Bë™F ›Ë)™Bë
+Bë
+Bë
+
+BëëÝøh€F•Fë
+,Bë %Ië ˜ABë ë $‘Lë ™Ë™Bëë  “Gë"“›£û4™Íé4›£û4Íé4›™Ýø`€˜£û«™£û4™Íé 4›£û4™Íé
+4›£û4™Íé4›£û4™Íé4›Ýø£û4™ëBëFë
+
+œëBëv ™BëaœBëÍ ›Bë™›Bë äLë [Bëë ›WAë ÝøhBë ÛŸLë ë ÝøpBë
+—ë
+’FBë ë—F(˜Kë Ýøœ€‘F8Bëë
+pBë@ BëFéBë
+:FIë 0Fë
+Ië%Ië ©Fë
+ÝøpÝøh Lë ë Fë %•ëgFLë ­Ië $•ëÝø`€ žCëëCëë Cë"•ö
+ŸLë  –}•Lë ,Lë ¤”Lë œ FCëë
+
+CëöCëÍé
+Ýøë
+Cë ë—F"˜Kë Ýø€€8Cëë
+’@ë’¥ûg1F:Fë
+Cëë
+Cë LCë&Fë
+Ýø  Cëë
+Ýø Në”ëÝø€Cëë^A”ëÝøCëë Në¤Në”tFëÝøD€Cë”4FžëCë
+™Cë6_AÝø€Š™Cë ÒKë Ýø
+‘ĸëcë̹ë cë
+cëñÿ7OêÑ|Cñÿ0·ë `ë
+™ Fþ÷ ýšF ™ Fþ÷šýš‚F™ Fþ÷”ý›Ãé
+ÃøÃø €a]ažaÃø°-°½èð-éðOFh‡°hLhðPh´ë
-ÛII’
- l$$Hä\\¸]ŸnÓӽשּׁC¦bbĨ‘‘9¤••17ääÓ‹yyò2ççÕCÈÈ‹Y77n·mmÚŒdÕÕ±ÒNNœà©©I´llØúVV¬ôôó%êêϯeeÊŽzzôé®®GÕººoˆxxðo%%Jr..\$8ñ¦¦WÇ´´sQÆÆ—#èèË|ÝÝ¡œttè!>ÝKK–ܽ½a†‹‹ …ŠŠppàB>>|ĵµqªffÌØHHöö÷£aaÂ_55jùWW®Ð¹¹i‘††XÁÁ™':¹žž'8ááÙøø볘˜+3"»iiÒpÙÙ©‰ŽŽ§””3¶››-"<’‡‡ ééÉIηÿUUªx((PzßߥŒŒø¡¡Y€‰‰  Ú¿¿e1ææ×ÆBB„¸hhÐÃAA‚°™™)w--ZË°°{üTT¨Ö»»m:,c|w{òkoÅ0g+þ׫vÊ‚É}úYGð­Ô¢¯œ¤rÀ·ý“&6?÷Ì4¥åñqØ1Ç#Öš€âë'²u ƒ,nZ R;Ö³)ã/„SÑ
-I$\ÂÓ¬b‘•äyçÈ7mÕN©lVôêez®ºx%.¦´ÆèÝtK½‹Šp>µfHöa5W¹†Ážáø˜iÙŽ”›‡éÎU(ߌ¡‰ ¿æBhA™-°T»
-ñ
-ø'@êGø(Pêø)`ê)ø
-]øû
- ËøàÀ
-õ€vOðÿêeêGøPê(øpê ø€Eêeø EêEVøKEê %…ê€ê
-õ€vOðÿOð êeêGøPê(øpê ø€Eêeø EêEVøKEê %…ê €ê
-õ€vOðÿOð êeêGøPê(øpê ø€Eêeø EêEVøKEê %…ê €ê
-|¡éB|É„ø
-!¦\hÑT[›:.6$±g
- çW“Ò–î´ž‘›OÅÀ€¢ ÜaiKwZ
-º“âå* ÀCà"< ­Ç‹ò¹¨¶-È©…ñWLu¯»Ý™îý`£Ÿ&÷¼õr\Å;fD4~û[v)C‹ÜÆ#Ëhüí¶cñä¸ÊÜ1×…cB@"— Æ„}$J…ø=»Ò2ù®m¡)ÇK/žó0²ÜìR† ÐãÁwl³+™¹p©úH”"déGÄŒü¨?ð Ø,}Vï3"ÇNI‡ÁÑ8Ùþ¢ÊŒ6 Ô˜Ïõ¦(Þz¥&Ž·Ú¤¿­?ä:, ’xP›Ì_jbF~TÂöè¸Ø^÷9.õ¯Ã‚¾€]Ÿ|“Ði©-Õo³%Ï;™¬È§}ncœè{»;Û x&ÍôYn·šì¨šOƒen•æ~æÿªϼ!æèïÙ›çºÎ6oJÔ ŸêÖ|°)¯²¤11#?*0”¥ÆÀf¢57¼Nt¦Ê‚ü°Ðàا3J˜ñ÷ÚìAPÍ/ö‘ÖMvM°ïCTMªÌß–äãµÑžˆjL¸,ÁQeFê^]5Œst‡ú.A ûZg³RÒÛ’3VéGÖmŒaךz ¡7ŽøY‰<ëî'©Î5Éa·íåá<±GzYßÒœ?sòUyο7ÇsêÍ÷S[ªý_o=߆ÛDxó¯Ê>Äh¹,4$8_@£Ârà %⼋I<(A• ÿq¨9Þ³ œä´ØÁVda„Ë{p¶2Õt\lHBW¸ÐR jÕ06¥8¿@£žó×û|ã9‚›/ÿ‡4ŽCDÄÞéËT{”2¦Â#=îL• BúÃN.¡f(Ù$²v[¢Im‹Ñ%røöd†h˜Ô¤\Ì]e¶’lpHPýí¹Ú^FW§„Ø«
-÷äX¸³EÐ,Ê?Á¯½Šk:‘AOgÜê—òÏÎð´æs–¬t"ç­5…âù7èußnGñq)ʼno·bª¾üV>KÆÒy šÛÀþxÍZôݨ3ˆÇ1±Y'€ì_`Q©µJ -åzŸ“Éœï à;M®*õ°Èë»<ƒS™a+~ºwÖ&áicU! }¯ò-éò_£õ j„F“FÜø
-õ€jÚø
-ëaøp xø€‡ê
-ëbx€ê ø ˆêAêG…êBê(øp†ê Fø€ê
-ëcø x€ê@Ûø
-
-0àã€
-N
-À ã<
-`ô ãÀ ãjô„Iðó…YðóF,ðò
-Bô
-GLüó`,ðò
-"ô* ô„
-
-"ô* ôÀ°óÂ#°ó„
-
-"ôÀ°ó
-
-"ôJ ô0Câ*"ô
-"ô0SâC°ó„C°ó*"ô÷ÿÿÊ
-"ôC°óPAóJôÿ/á
-"ôJ ô0Câ*"ô@C°óÄC°ó
-"ô0SâBC°óÄC°ó*"ô÷ÿÿÊ@C°óÄC°ó
-"ôBC°óPAóJôÿ/á
- ôcôPEârƒàPEâBgô‚gôÂgôê'ô pƒâ` á_
-
-B'ôpƒâ@`ƒâPÀƒâ °ó€°ó`àƒâp0ƒâ
-fô
- °ó€°ó
-nô"°ó€°ó*cô
-`ô(°ó€°óÚ@ó*°ó€°ó*gô,°ó€°ó.°ó^Á
-`ô(°ó€°ó*°ó€°ó,°ó€°óÚ@ó.°ó^Á
-gô`Vâb°óÀ°ób#°óÂ#°óbCðóäCðó*gôïÿÿÊ`°óÀ°ó`#°óÂ#°ó`CðóäCðó^ ó0 Râ^¡ó` 1b°óÀ°ób#°óÂ#°óbCðóäCðó^!Fó
-gô`…âPóR¡
-óòADó*gô ŠôT$ò ªôV!&ò JAôöAfò¶ÿÿ*0
-
-gô`Vâb#°óÂ#°óbCðóäCðó*gôóÿÿÊ`#°óÂ#°ó`CðóäCðób#°óÂ#°óbCðóäCðóh#°óÂ#°óhCðóäCðó
-R¡
-óô!BóöÁ&ò ªô *Aô
-óöÁ&ò ªôÊô‹½ìð½è
-$ôcôPEâÀ ã
-gô`Vâ"°ó€°ó"#°ó‚#°ó"Cðó¤Cðó*gôïÿÿÊ °ó€ƒ°ó #°ó‚£°ó J ô\,ò Cðó¤Cðó j ô\!,ò"ƒ°óˆƒ°ó"£°óŠ£°ó j`ôp á"Cðó¤#ðó\Alòˆâ(ƒ°óˆƒ°ó(£°óŠ£°ó^Aó ˆâ(#ðó¢#ðó^aó€ˆâ*ƒ°óˆƒ°ó*£°óŠ£°óÞaFó9Ÿ¿æ*#ðó¢#ðó›!î:¯¿æ,ƒ°óˆƒ°ó,£°óŠ£°ó«#î8Ï¿æ,#ðó¢#ðóË%î Râ.ƒ°ó.£°ó.#ðóXAó
-gô JôZaó` á jôòaFó*gô jAô°ÿÿ* ’â.
-
-gô`Vâ"°ó€°ó"#°ó‚#°ó*gôóÿÿÊ °ó€°ó #°ó‚#°ó"°ó€°ó"#°ó‚#°ó J ô(°ó€°ó(#°ó‚#°ój ô*°ó€°ó*#°ó‚#°ó^Aó,°ó€°ó,#°ó‚#°ó^aó.°ó.#°ó
-jô‹½ìð‡½è
-ûøOð
- DøËNñ
-ûøOð
-SøkOð
- DøËNñ
-ÐïÕìÿá*}ïŒØÿmï¾ÙìÿÂJ#ùBìÿâjìÿÊöÿˆÑìÿ㪭ÿÄÂ¥ñ ­ÿäâíÿÅíÿå"íÿÆB,ï\¡íÿæb.ï^ÁíÿÇ‚ ïðáíÿç¢bïòdïô!°ÿš fïöAhïøa:ï ¨jïúJÿú¡°ÿš à
-ȬÿÀ¬ÿàâìÿÁÐïÕìÿá"}ïŒØÿ¹ñ mï¾ÙìÿÂBìÿâbìÿÂöÿˆÑìÿ㢭ÿÄ­ÿäâíÿÅíÿå"íÿÆB,ï\¡íÿæb.ï^ÁíÿÇ‚ ïðáíÿç¢bïòdïô!°ÿš fïöAhïøa:ï ¨jïúJÿú¡°ÿš ²Ñ<ï
-ÈoF°ÿœ ¨F=ï
-Ø®°ÿ ¶ÿÁÔã
-äù?è©F
-ÿ¡­ÿäâöÿŠÁíÿÅ°ÿœÀíÿå"íÿÆB<ï Èíÿæb°ÿœÀíÿÇ‚íÿç¢>ï èJù׬ÿÀâ&ùíÊìÿàÿìÿÁ"ÐïŸÕìÿáB}ïŽØìÿÂbmï¾Ùìÿâ‚JùÇìÿâöÿˆÑ¬ÿãÂâù=È­ÿÄâ
-ÿ¡íÿäöÿŠÁíÿÅ"°ÿžàíÿåBíÿÆb>ïèíÿæ‚°ÿžàíÿÇ¢­ÿçÂpïŽJù×ìÿÀ&ùíêìÿà"ÿìÿÁBÐï±Õìÿáb}ï Øìÿ‚mï¾Ùìÿâ¢JùǬÿÃÂöÿˆÑ¬ÿãââù=ÈíÿÄ
-ÿ¡íÿä"öÿŠÁíÿÅBðÿ°
-ìÿàBÿìÿÁbÐï³Õìÿá‚}ï¢Øìÿ¢mï¾Ù¬ÿâÂJùǬÿÃâöÿˆÑìÿãâù=ÈíÿÄ"
-ÿ¡íÿäBöÿŠÁíÿÅbðÿ² íÿå‚íÿÆ¢rï£(­ÿæÂðÿ² ­ÿÇâíÿçtï¢HJù×ìÿÀBfùí*ìÿàbÿìÿÁ‚ÐïµÕìÿá¢}ï¤Ø¬ÿÂÂmï¾Ù¬ÿââJùÇìÿÃöÿˆÑìÿã"âù=ÈíÿÄB
-ÿ¡íÿäböÿŠÁíÿÅ‚ðÿ´@íÿ墭ÿÆÂtï¥H­ÿæâðÿ´@íÿÇíÿç"vï¤hJù×ìÿÀbfùíJìÿà‚ÿìÿÁ¢Ðï·Õ¬ÿáÂ}ï¦Ø¬ÿÂâmï¾ÙìÿâJùÇìÿÃ"öÿˆÑìÿãBâù=ÈíÿÄb
-ÿ¡íÿä‚öÿŠÁíÿÅ¢ðÿ¶`­ÿå­ÿÆâvï§híÿæðÿ¶`íÿÇ"íÿçBx麗Jù×ìÿÀ‚fùíjìÿà¢ÿ¬ÿÁÂÐï¹Õ¬ÿáâ}ï¨ØìÿÂmï¾Ùìÿâ"JùÇìÿÃBöÿˆÑìÿãbâù=ÈíÿÄ‚
-ÿ¡íÿä¢öÿŠÁ­ÿÅÂðÿ¸€­ÿåâíÿÆx煮íÿæ"ðÿ¸€íÿÇBíÿçbz﨨Jù×ìÿÀ¢fù튬ÿàÂÿ¬ÿÁâÐï»Õìÿá}ïªØìÿÂ"mï¾ÙìÿâBJùÇìÿÃböÿˆÑìÿã‚mùŸÇíÿÄ¢!ù­ÿä­ÿÅâðÿº íÿåíÿÆ"z﫨íÿæBðÿº íÿÇbíÿç‚<ï*ÈJùŸ× ñ
-¥ñà¯ó
-ìÿÀ"fùï
-ìÿàBjù×ìÿÁb¿6ìÿá‚ìÿ¢¬ÿâ¬ÿÃâìÿãjùÇíÿÄ"íÿäBíÿÅbíÿå‚íÿÆ¢­ÿæ­ÿÇâíÿçGùí*ìÿÀBfùï*ìÿàbjù×ìÿÁ‚¿6ìÿ᢬ÿ¬ÿââìÿÃìÿã"jùÇíÿÄBíÿäbíÿÅ‚íÿ墭ÿÆ­ÿæâíÿÇíÿç"GùíJìÿÀbfùïJìÿà‚jù×ìÿÁ¢¿6¬ÿá¬ÿÂâìÿâìÿÃ"ìÿãBjùÇíÿÄbíÿä‚íÿÅ¢­ÿå­ÿÆâíÿæíÿÇ"íÿçBGùíjìÿÀ‚fùïjìÿà¢jù׬ÿÁ¿6¬ÿáâìÿÂìÿâ"ìÿÃBìÿãbjùÇíÿÄ‚íÿ䢭ÿÅ­ÿåâíÿÆíÿæ"íÿÇBíÿçbGùíŠìÿÀ¢fùÿàÂjù׬ÿÁâ¿6ìÿáìÿÂ"ìÿâBìÿÃbìÿã‚¿¡ë…íÿÄ¢mùŸÇ­ÿäÂ!ù­ÿÅâ ñ
-íÿåíÿÆ"íÿæBíÿÇbGùíªíÿç‚ô£® ®ùýÂÿTAGùýÿVaGùýBGùñ &ùýÂfùýfùýBfùý‚¿£ë…‡ä ¯ ùýB°ÿœ  ùýB=ï
-Ø ùýB°ÿ  ùýB¶ÿÁ¨Fà
-È°ÿœ fùý=ï
-ØfùýB°ÿ fùý‚¶ÿÁ>ï
-è‡ù=È°ÿž ?ï
-ø°ÿŸ ¶ÿápù=è°ÿ° qÿ± öÿ¡rïŠ(Çù=°ÿ² sïŠ8°ÿ³ öÿ£!tïŠHÇù=(°ÿ´ uïŠX°ÿµ öÿ¥AvïŠhÇù=H°ÿ¶ wïŠx°ÿ· öÿ§axÇù=h°ÿ¸ y°ÿ¹ öÿ©zÇù=ˆ°ÿº {°ÿ» öÿ«¡&ùý¸ñÇù=¨”чù?¨£ë…½ñ
+ië OêÜ{°ëSi`ë
+ ŸDëÝø 1F&Fë £FDëÅø À2F)aÒDëëDñ
+ja0DÅé
+ëa°½èð h-éðO‘°FˆhÓñ
+Kñ
+këK Íé«›Ü"Eñ
+ ›Ü ziEñ
-wë ‘ê è
-ðÉè
-ëóg™ú‰ùêº
-ODŠê¶
-NøWDQø›ë¶„ê
-ë÷f™ú‰ùêº
-NDŠêµ
-NøVDQø›ëµƒê
-ëöe™ú‰ùêº
-MDŠê´
-NøUDQø›ë´‡ê
-ëõd™ú‰ùêº
-LDŠê³
-NøTDQø›ë³†ê
-ëôc™ú‰ùêº
-KDŠê·
-NøSDìFžê ¡Ñ™°Qø›ë·…ê
-ëóg™ú‰ùêº
-ODŠê¶
-NøWDÞø<Þø4 Þø°ë¶ÞøÀ‰ê
- ‹ê „ê
-Oêùyë÷f‰êûyNøêº
-NDŠêµ
-VDÞø<Þø4 Þø°ëµÞøÀ‰ê
- ܐ Đ
-Oêùyëöe‰êûyNøêº
-MDŠê´
-UDÞø<Þø4 Þø°ë´ÞøÀ‰ê
- ‹ê ‡ê
-Oêùyëõd‰êûyNøêº
-LDŠê³
-TDÞø<Þø4 Þø°ë³ÞøÀ‰ê
- ‹ê †ê
-Oêùyëôc‰êûyNøêº
-KDŠê·
-SDßø´‚ñ
- ‹ê …ê
-Oêùyëóg‰êûyNø„êº
-ODWDÞø<Þø4 Þø°ë¶ÞøÀ‰ê
- ‹ê „ê
-Oêùyë÷f‰êûyNøƒêº
-NDVDÞø<Þø4 Þø°ëµÞøÀ‰ê
- ܐ Đ
-Oêùyëöe‰êûyNø‡êº
-MDUDÞø<Þø4 Þø°ë´ÞøÀ‰ê
- ‹ê ‡ê
-Oêùyëõd‰êûyNø†êº
-LDTDÞø<Þø4 Þø°ë³ÞøÀ‰ê
- ‹ê †ê
-Oêùyëôc‰êûyNø…êº
-KDSDìFžê ôo¯€ð®€ßøˆ”°Þø<Þø4 Þø°ë·ÞøÀ‰ê
- ‹ê …ê
-Oêùyëóg‰êûyNøêº
-ê ODWDë»Þø<Þø4 Þø°ë¶ÞøÀ‰ê
- ‹ê „ê
-Oêùyë÷f‰êûyNøêº
-ê NDVDë»Þø<Þø4 Þø°ëµÞøÀ‰ê
- ܐ Đ
-Oêùyëöe‰êûyNøêº
-ê MDUDë»Þø<Þø4 Þø°ë´ÞøÀ‰ê
- ‹ê ‡ê
-Oêùyëõd‰êûyNøêº
-ê LDTDë»Þø<Þø4 Þø°ë³ÞøÀ‰ê
- ‹ê †ê
-Oêùyëôc‰êûyNøêº
-ê KDSDë»ìFžê ô[¯ßø<€”°½ñ
-ëµ ë¶ ë·€èø
-dïlHLù­*Lù­JÝø
-ODê fïl¨Ýøëógöïn„‹ê
- Oê´_D@ÿÐ%ê
-NDHÿÔê ÝøHÿðë÷f‹ê
- Lù­ª¬ñ@ Oê³^Dþïè¤$ê
-MDhïèê Ýø áÿxëöe‹ê
- Oê·âÿz€]D#ê
-âïz¥LDê @ÿøÝøëõd@ÿú‹ê
- Oê¶\DòïD('ê
-KDê `ïì¨Ýøèù½Ìëôcðïî„‹ê
- Oêµ[DBÿÒ!&ê
-ODHÿÖê ÝøHÿòëóg‹ê
- Lù­ªOê´_Dþïè¤%ê
-NDhïè(ê Ýøáÿx$ë÷f‹ê
- Oê³âÿz€^D$ê
-âïz¥MDê Bÿø!Ýø ëöeBÿú!‹ê
- Oê·]DôïFH#ê
-LDê bïì¨Ýø$ëõdòïî„‹ê
- Oê¶\DDÿÔA'ê
-KDHÿðê Ýø(Hÿôëôc‹ê
- Lù­ªOêµ[Dþïè¤&ê
-ODhïèHê Ýø,áÿxDëóg‹ê
- Oê´âÿz€_D%ê
-âïz¥NDê DÿøAÝø0ë÷fDÿúA‹ê
- Oê³^Döï`h$ê
-MDê dïì¨Ýø4ëöeôïî„‹ê
- Oê·]DFÿÖa#ê
-LDHÿòê Ýø8Hÿöëõd‹ê
- Lù­ªOê¶\Dþïè¤'ê
-KDhïèhê Ýø<áÿxdëôc‹ê
- Oêµâÿz€[D&ê
-âïz¥ODê FÿøaÝø
- Oê´_Dôïæˆ%ê
-NDê
- Oê³fïì¨^D$ê
-HÿÐMDê ¢ÿx
- Oê·¢ÿx]D#ê
-LDê Ýø ëõd‹ê
- Oê¶\D'ê
-KDê Ýøëôc‹ê
- Oêµ[DöïÀˆ„ê
-ODÝøÿr!Šê ëógÿT!Oê´_D`ïl¨ƒê
-NDHÿÒÝøŠê ¢ÿx ë÷fOê³Lù­ª^D‡ê
-¢ÿx%MDÝøŠê ëöeOê·]D†ê
-LDÝø Šê ëõdOê¶\DðïBˆ…ê
-KDÝø$ÿtAŠê ëôcÿVAOêµ[Dbïl¨„ê
-èù½ÌODHÿÔÝø(Šê ¢ÿx@ëógOê´Lù­ª_Dƒê
-¢ÿxENDÝø,Šê ë÷fOê³^D‡ê
-MDÝø0Šê ëöeOê·]DòïDˆ†ê
-LDÝø4ÿvaŠê ëõdÿpaOê¶\Ddïl¨…ê
-KDHÿÖÝø8Šê ¢ÿx`ëôcOêµLù­ª[D„ê
-¢ÿxeODÝø<Šê ëógOê´_Dƒê
-NDÝø
-MDÝø@ÿЊê ëöe@ÿòOê·]Dfïl¨†ê
-LDHÿðÝøŠê âÿx
-âÿxKDÝø Šê ëôcOêµ[D„ê
-ODÝøŠê ëógOê´_Döï`ˆƒê
-NDÝøBÿÒ!Šê ë÷fBÿô!Oê³^D`ï쨇ê
-MDHÿòÝøŠê âÿx ëöeOê·Lù­ª]D†ê
-âÿx%LDÝøŠê ëõdOê¶\D…ê
-KDÝø Šê ëôcOêµ[DðïâˆODê
-Ýø$DÿÔAëóg…ê DÿöAWD ê bïì¨Oê´_DHÿôNDê
-âÿx@Ýø(ë÷fLù­ª„ê VDâÿxE ê Oê³^DMDê
-Ýø,ëöeƒê UD ê Oê·]DLDê
-Ýø0ëõd‡ê TD ê Oê¶\DòïäˆKDê
-Ýø4FÿÖaëôc†ê FÿÐaSD ê dïì¨Oêµèù½Ì[DHÿöODê
-âÿx`Ýø8ëógLù­ª…ê WDâÿxe ê Oê´_DNDê
-Ýø<ë÷f„ê VD ê Oê³^DMDê
-Ýø
-Ýø
-¢ÿx
-Ýø ëóg…ê WD ê Oê´_DNDê
-Ýøë÷f„ê VD ê Oê³^DöïÀˆMDê
-Ýøÿr!ëöeƒê ÿT!UD ê `ïl¨Oê·]DHÿÒLDê
-¢ÿx ÝøëõdLù­ª‡ê TD¢ÿx% ê Oê¶\DKDê
-Ýøëôc†ê SD ê Oêµ[DODê
-Ýø ëóg…ê WD ê Oê´_DðïBˆNDê
-Ýø$ÿtAë÷f„ê ÿVAVD ê bïl¨Oê³^DHÿÔMDê
-¢ÿx@Ýø(ëöeLù­ªƒê UD¢ÿxE ê Oê·]DLDê
-Ýø,ëõd‡ê TD ê Oê¶\DKDê
-Ýø0ëôc†ê SD ê Oêµ[DòïDˆ„ê
-ODÝø4ÿvaŠê ëógÿpaOê´_Ddïl¨ƒê
-NDHÿÖÝø8Šê ¢ÿx`ë÷fOê³Lù­ª^D‡ê
-¢ÿxeMDÝø<Šê ëöeOê·]D†ê
-LDÝø
-KDLù­ª¬ñ@ ‘ê¨ñ¿@9!ù ÝøŠê !ù BëôcOêµèù½Ì[D„ê
-°ÿÀ
-NDÝø Šê ë÷fOê³^D‡ê
-MDÝøŠê ëöeOê·]D°ÿ †ê
-LD`ïlÝøŠê Lù­
-ëõdOê¶\D…ê
-KDÝøŠê ëôcOêµ[D„ê
-ODÝøŠê ëógOê´_Dƒê
-NDÝø Šê ë÷fOê³^D°ÿÄ@‡ê
-MDbïl(Ýø$Šê Lù­*ëöeOê·]D†ê
-LDÝø(Šê ëõdOê¶\D…ê
-KDÝø,Šê ëôcOêµ[D„ê
-ODÝø0Šê ëógOê´_D°ÿÆ`ƒê
-NDdïlHÝø4Šê Lù­Jë÷fOê³^D‡ê
-MDÝø8Šê ëöeOê·]D†ê
-LDÝø<Šê ëõdOê¶\D…ê
-KDŠê ëôcOêµ[Dè
- ù( ñ
-€ù(½ì‹pG¯ó
-·'8!.üm,M 8STs
-e»
-jv.ÉÂ…,r’¡è¿¢Kf¨p‹K£QlÇè’Ñ$™Ö…5ôp jÁ¤l7LwH'µ¼°4³ 9JªØNOÊœ[óo.hî‚toc¥xxÈ„ÇŒúÿ¾ëlP¤÷£ù¾òxqÆ
- ë°êãD‚ê
-„êô “DQø+„ê €ê4Pê _Dƒê ë° ‡êw›D€ê÷@º^ø;’D’ˆê 
-ë°êšD‚ê ‹êû ’DQø+‹ê€ê;P ê VDŒê
-ë°
-†êvâD€êö@º^øË‘D’‡ê ë°êáD‚êŠêú ‘DQø+Šê €ê:Pê MDƒê  ë° …êu™D€êõ@º^ø;D’†êë°ê˜D‚ê‰êù DQø+‰ê
-€ê9P ê DDŒê
- ë°„êtàD€êô@º^øËD’…êë°êgD‚êˆêø DQø+ˆê €ê8Pê »Dƒê ë°‹ê{D€êû@º^ø;D’„êë°ê D‚ê‡ê÷ DQø+‡ê€ê7P ê ²DŒê ë°ŠêzfD€êú@º^øËD’‹êë°ê
-eD‚ê†êö DQø+†ê €ê6Pê ©Dƒêë°‰êyD€êù@º^ø;D’Šê ë°ê D‚ê …êõ DQø+…ê€ê5P ê  DŒê ë°ˆêxdD€êø@º^øË“D’‰ê
- ë°êãD‚ê
-„êô “DQø+„ê €ê4Pê _Dƒê ë° ‡êw›D€ê÷@º^ø;’D ’ˆê 
-ë°êšD‚ê ‹êû ’DQø+‹ê€ê;P ê VDŒê
-ë°
-†êvâD€êö@º^øË‘D
-’‡ê ë°êáD‚êŠêú ‘DQø+Šê €ê:Pê MDƒê  ë° …êu™D€êõ@º^ø;D ’†êë°ê˜D‚ê‰êù DQø+‰ê
-€ê9P ê DDŒê
- ë°„êtàD€êô@º^øËD ’…êë°êgD‚êˆêø DQø+ˆê €ê8Pê »Dƒê ë°‹ê{D€êû@º^ø;D ’„êë°ê D‚ê‡ê÷ DQø+‡ê€ê7P ê ²DŒê ë°ŠêzfD€êú@º^øËD’‹êë°ê
-eD‚ê†êö DQø+†ê €ê6Pê ©Dƒêë°‘‰êyD€êù@º^ø;D’Šê ë°ê D‚ê …êõ Dš…Ꙁê5P ê  DŒê ë°OêòdDOêqL€ê²@ŒêñL€êÒ
-D^øË“D
- ë°êãD‚ê
-„êô “Dš„ê ™€ê4Pê _Dƒê ë° Oêò›DOêqC€ê²@ƒêñC€êÒ
-™D‡êwD€ê÷@
-D^ø;’D’ˆê 
-ë°êšD‚ê ‹êû ’Dš‹ê
-ë°
-OêòâDOêqL€ê²@ŒêñL€êÒ
-D^øË‘D’‡ê ë°êáD‚êŠêú ‘DšŠê ™€ê:Pê MDƒê  ë° Oêò™DOêqC€ê²@ƒêñC€êÒ
-D^ø;D’†êë°ê˜D‚ê‰êù Dš‰ê
-™€ê9P ê DDŒê
- ë°OêòàDOêqL€ê²@ŒêñL€êÒ
-D^øËD’…êë°êgD‚êˆêø Dšˆê ™€ê8Pê »Dƒê ë°OêòDOêqC€ê²@ƒêñC€êÒ
-D^ø;D’„êë°ê D‚ê‡ê÷ Dš‡ê™€ê7P ê ²DŒê ë°OêòfDOêqL€ê²@ŒêñL€êÒ
-D^øËD’‹êë°ê
-eD‚ê†êö Dš†ê ™€ê6Pê ©Dƒêë°OêòDOêqC€ê²@ƒêñC€êÒ
-D^ø;D’Šê ë°ê D‚ê …êõ D š…Ꙁê5P ê  DŒê ë°OêòdDOêqL€ê²@ŒêñL€êÒ
-D^øË“D’‰ê
- ë°êãD‚ê
-„êô “D
-š„ê ™€ê4Pê _Dƒê ë° Oêò›DOêqC€ê²@ƒêñC€êÒ
-D^ø;’D ’ˆê 
-ë°êšD‚ê ‹êû ’D š‹ê™€ê;P ê VDŒê
-ë°
-OêòâDOêqL€ê²@ŒêñL€êÒ
-šŒê‘,™„D†êvbD€êö@
-D^øË‘D
-’‡ê ë°êáD‚êŠêú ‘D šŠê ™€ê:Pê MDƒê  ë° Oêò™DOêqC€ê²@ƒêñC€êÒ
-D^ø;D ’†êë°ê˜D‚ê‰êù D š‰ê
-
-™€ê9P ê DDŒê
- ë°OêòàDOêqL€ê²@ŒêñL€êÒ
-D^øËD ’…êë°êgD‚êˆêø Dšˆê ™€ê8Pê »Dƒê ë°OêòDOêqC€ê²@ƒêñC€êÒ
-D^ø;D ’„êë°ê D‚ê‡ê÷ Dš‡ê ™€ê7P ê ²DŒê ë°OêòfDOêqL€ê²@ŒêñL€êÒ
-D^øËD’‹êë°ê
-eD‚ê†êö D
-D^ø;D’Šê ë°ê D‚ê …êõ Dðÿò+š…Ꙁê5P ê  DŒê ë° ¿›ÉädDhZhÓøÀDØhDifDÓøÀD˜iDÚiáD™ÝøHÀ‚D“DƒèðaE®õ€~ôvª°½èð¯ó
-!ù *!ù J!ù jnù­
-nù­*nù­Jnù­j°ÿÀ
-dïÄHAù­*fïÆhAù­JAù­jèð¡ñ@
-ˆêxôïF$dDê€êøLùÿp@„êô ‚ê
- ïb 뼄ê ýÿp €ê4P“DùÿpEšê îÿp`_D ë° ƒêBÿô!’Dîÿpeˆê ‡êwïÿ€›DêBÿö!€ê÷C‹êû ïÿ…‚ê 
-ë³öÿ‹ê€ê;P ïb’DšIÿ¸‘ ê VDíÿ€
-ë°
-Œê íÿ…‘D‡êIÿ¸‘†êvâD ï)ê€êöLïÿ€Šêú ‚êïÿ… 뼊ê öÿ€ê:P‘DIÿ¸‘šê íÿ€MD ë° ƒê nù­
-Díÿ…†ê…êuIÿ¸‘™Dê!ï)€êõC‰êù `ïÀ‚ê볉ê
-€ê9PDš ê DDAù­
-ë°Œê
- òïDD…ê„êtöï@$àDê€êôLùÿp@ˆêø ‚ê"ïb(뼈ê ýÿp €ê8PDùÿpEšê îÿp`»Dë°ƒê Bÿô!Dîÿpe„ê‹ê{ïÿ€Dê Bÿö!€êûC‡ê÷ ïÿ…‚êë³öÿ‡ê€ê7P"ïb(DšIÿ¸‘ ê ²Díÿ€ë°Œê íÿ…D‹êIÿ¸‘ŠêzfD"ï)(ê
-€êúLïÿ€†êö ‚êïÿ…뼆ê öÿ€ê6PDIÿ¸‘šê íÿ€©Dë°ƒênù­
-Díÿ…Šê ‰êyIÿ¸‘Dê #ï)8€êùC…êõ `ï‚ê ë³…ê€ê5PDš ê  DAù­
-ë°Œê ôïF“D‰ê
-ˆêxðïB$dDê€êøLùÿp@„êô ‚ê
-$ïbH 뼄ê ýÿp €ê4P“DùÿpE šê îÿp`_D ë° ƒêBÿô!’Dîÿpeˆê ‡êwïÿ€›DêBÿö!€ê÷C‹êû ïÿ…‚ê 
-ë³öÿ‹ê€ê;P$ïbH’D
-šIÿ¸‘ ê VDíÿ€
-ë°
-Œê íÿ…‘D‡êIÿ¸‘†êvâD$ï)Hê€êöLïÿ€Šêú ‚êïÿ… 뼊ê öÿ€ê:P‘DIÿ¸‘ šê íÿ€MD ë° ƒê nù­
-Díÿ…†ê…êuIÿ¸‘™Dê%ï)X€êõC‰êù `ïÄ‚ê볉ê
-€ê9PD š ê DDAù­
-ë°Œê
- öï@D…ê„êtòïD$àDê€êôLùÿp@ˆêø ‚ê&ïbh뼈ê ýÿp €ê8PDùÿpE šê îÿp`»Dë°ƒê Bÿô!Dîÿpe„ê‹ê{ïÿ€Dê Bÿö!€êûC‡ê÷ ïÿ…‚êë³öÿ‡ê€ê7P&ïbhDšIÿ¸‘ ê ²Díÿ€ë°Œê íÿ…D‹êIÿ¸‘ŠêzfD&ï)hê
-€êúLïÿ€†êö ‚êïÿ…뼆ê öÿ€ê6PDIÿ¸‘šê íÿ€©Dë°ƒênù­
-Díÿ…Šê ‰êyIÿ¸‘Dê 'ï)x€êùC…êõ `ïÆ‚ê ë³…ê€ê5PDÞø
-ë°Œê ’ð
-!ù *!ù J!ù j¿‘iF“D‰ê
-ˆêxdDnù­
-ê€êøL„êô ‚ê
-°ÿÀ
-볋ê€ê;P’Dš ê VD
-ë°
-Œê ‘D‡ê†êvâDê€êöLŠêú ‚ê ë¼Šê €ê:P‘Dšê MD ë° ƒê D†ê…êu™Dê€êõC‰êù ‚ê볉ê
-€ê9PDš ê DDë°Œê
- Aù­
-D…ê„êtàDnù­
-ê€êôLˆêø ‚ê°ÿ ë¼ˆê €ê8PD`ïÂšê »Dë°ƒê D„ê‹ê{Dê €êûC‡ê÷ ‚ê볇ê€ê7PDš ê ²Dë°Œê D‹êŠêzfDê
-€êúL†êö ‚êë¼†ê €ê6PDšê ©Dë°ƒêDŠê ‰êyDê €êùC…êõ ‚ê ë³…ê€ê5PDš ê  Dë°Œê Aù­
-“D‰ê
-ˆêxdDnù­
-ê€êøL„êô ‚ê
-°ÿÄ@ ë¼„ê €ê4P“D`ïÄ šê _D ë° ƒê’Dˆê ‡êw›Dê€ê÷C‹êû ‚ê 
-볋ê€ê;P’D
-š ê VD
-ë°
-Œê ‘D‡ê†êvâDê€êöLŠêú ‚ê ë¼Šê €ê:P‘D šê MD ë° ƒê D†ê…êu™Dê€êõC‰êù ‚ê볉ê
-€ê9PD š ê DDë°Œê
- Aù­
-D…ê„êtàDnù­
-ê€êôLˆêø ‚ê°ÿÆ`ë¼ˆê €ê8PD`ïÆ šê »Dë°ƒê D„ê‹ê{Dê €êûC‡ê÷ ‚ê볇ê€ê7PDš ê ²Dë°Œê D‹êŠêzfDê
-€êúL†êö ‚êë¼†ê €ê6PDšê ©Dë°ƒêDŠê ‰êyDê €êùC…êõ ‚ê ë³…ê€ê5PDš ê  Dë°Œê Aù­
-hdDÒøÀ“hÑhDieDÒøÀD“iDÑi€DBøKáDBø[šDBøk‹DBø{‚è
-“G‘§Õo‚àQcÊpn
-g))ü/ÒF…
-·'&É&\8!.í*ÄZüm,Mß³• 8SÞc¯‹Ts
-e¨²w<»
-jvæ®íG.ÉÂ;5‚…,r’dñL¡è¿¢0B¼Kf¨‘—øÐp‹KÂ0¾T£QlÇRïÖè’Ñ©eU$™Ö* qW…5ô¸Ñ»2p jÈÐÒ¸Á¤S«AQl7™ëŽßLwH'¨H›áµ¼°4cZÉų 9ËŠAãJªØNsãcwOÊœ[£¸²Öóo.hü²ï]î‚t`/Coc¥xr«ð¡xÈ„ì9dÇŒ(c#úÿ¾é½‚ÞëlP¤yƲ÷£ù¾+SrãòxqÆœa&êÎ>'ÊÂÀ!Ǹ†ÑëàÍÖ}ÚêxÑnîO}õºorªgð¦˜È¢Å}c
-® ù¾˜?G5 q„}#õwÛ(“$Ç@{«Ê2¼¾É
-¾ž<L œÄgC¶B>˾ÔÅL*~eüœ)YìúÖ:«oË_XGJŒDlÀr
-“ ”KhQøKº$ºOê—9“Oê˜:”‰êˆIÝø8°Šê‡JÝø<À‰ê—IŠê˜J‰êˆ9Šê‡:‰êX)ŠêW*‰êÇYŠêÈZë Ýø(Dë
-Ýø, ë Ýø0°Dë Ýø4À‰ê —Šê
-Íø$€ ê
-ê
-–‰ê Þø
-ÞøÀë ŸDë
-Ýø€ë  ðÿ Dë ÿÝø°Hë™ð”ÝøÀ¿NðOêyOêz‰êŠê‰ê– Šê•
-‰ê…yŠê†z‰êÖŠêÕ‰êEiŠêFjë ê Dë
-Ýø  Eê Ýø°ê ê
- Fê
-Eê ê íFê ‚°Fëðñð?ôc¯Ýø¸Ýø¼ .ðOêYÝøP°OêZÝøTÀƒêÊs„êÉtƒê#„ê$ƒê
-c„ê dƒêÙ„êÚƒêJcOêÛIOêÜJ‰êL9ŠêK:‰ê\yŠê[z‰êË ŠêÌ
-‰ê›ŠêœÝøx°‰êŒiÝø|Àë ÝøÀDë
-ÝøÄ ë Dë ë Dë
-Oê—9“Oê˜:”‰êˆIÝø8°Šê‡JÝø<À‰ê—IŠê˜J‰êˆ9Šê‡:‰êX)ŠêW*‰êÇYŠêÈZë Ýø(Dë
-Ýø, ë Ýø0°Dë Ýø4À‰ê —Šê
-Íø$€ ê
-ê
-–‰ê Þø
-ÞøÀë ŸDë
-Ýø€ë  ðÿ Dë ÿÝø°Hë™ðÝøÀ¿NðOêyOêz‰êŠê‰ê– Šê•
-‰ê…yŠê†z‰êÖŠêÕ‰êEiŠêFjë ê Dë
-Ýø  Eê Ýø°ê ê
- Fê
-Eê ê íFê ‚°Fëðñ¿Ýø¸Ýø¼ !ç.ð›œÐø
+ë
+
+Fþ÷Ô¼
+¬‰F‚FM™(FF ñH ’®ÿ÷ÅÿL™ Fÿ÷Áÿ"F9FXF ñˆþ÷‘ü*F9F0Fÿ÷þ*F9F@F*¯þ÷£ûBFAF8Fþ÷žû:FAF@Fþ÷™ûBF ñÈ1F@Fþ÷uüAFPFÿ÷šÿZFYF ñè XFþ÷‡ûZFYFXFþ÷‚ûZFYF8Fþ÷}û:FQFPFÿ÷êý*F!F(Fþ÷sûMš0FL™þ÷nû1F˜ÿ÷vÿ™*FFÿ÷×ýRFYFHFÿ÷Òý"F!F Fþ÷[û!F Fÿ÷cÿJFAFHFþ÷5ü"F!F Fþ÷Mû"FIFHFÿ÷ºýC°½èð-éðO­õ}‘ž‚F™F ñx ’œ0F‘’ÿ÷ÿ€F•˜ÿ÷ÿ1FFXFÿ÷9ÿ
+“ ›£õ$G
+›O?7D„ê.@f@>Dø|ëö6Hê(ø|HêHø |HêhfOÃDß›<D‚ê7@W@<Dø |ë´$Lê,ø
+|LêLø |Lêl[OGD:D…ê'@o@:Dø|ërbIê)ø|IêIø|IêiQOgD/D†ê@u@=Dø|ë5UNê.ø|NêNø|NênGOOD7D„ê.@f@>DDOëö6wD'D‚ê4@T@<D@Oë´$D›D†ê*@r@:D<OëòbD
+›/D„ê5@e@=D7OëõUß
+›.D‡êU@5D£NëuUD›>D„êo@7DŸNë7GND4D‚ê~@4DœNët$ž›D…êb@2D˜Në2rD ›.D‡êU@5D”NëuUVD7D„ên@7DNë7GD
+<DŠê
+TDfOë´TODdê ‰ê =DMDbOëuEDeê >D‰ê ND^Oëö&›GDfêˆê:DBDYOë²bDbê ›<DˆêUODDë´T£õ€£öƒ3+DdêU@D›ëuEDeêc@>DDKO›ëö&Dfêk@:DDGKë²bŸsDbêDŽêtDCKë´T;DdêW@D=D?OëuE›gDeê >DŒê ´D;Oëü,:NDlêk@:DŸ
+š7K ë·gDgê‚ê DD›ë´TDdê z@5DV›.JëvF…hDhbDfê Œê ”DBhD`2D.DÅhëü"†`B`,DÄ`)ä
+Bê"ø"<
+ê
+Šê
+BêBø!<BêbºÖJ“›ñµCõ3ò™˜Dø <@D
+ëðjGê'ø<GêGø<Gêg;ºø|
+“…ê@Oê°
+
+šg@Oêº
+ñµBõ2ò™Dø,/DëógNê.ø,NêNø,øÌNênžúŽò€ê
+ ’ê šŽê
+Dø,¦Dë÷nOê·Lê,ø,LêLø ,LêlœúŒòø Ì ’ šñµBõ2ò™Dø ,€Dø ëþhLê,ø
+,LêLø ,LêlœúŒòƒê ’ ê šŒê Oê¾ñµB‡êõ2êò™~@RDbDøÌëøbO긎êLê
+›†ê"@Oê´_@›r@_@Oê÷s Ÿ“ñµCõ3ò™œD›bDßøœÀëðb{@ Ÿ{@Ÿ{@Oêós“…êŸ@k@Oê°
+Šê
+p@
+žOêðp€DBDßø´ƒ”Dš ëûlOê» r@žr@žj@OêòrDCDßø”ƒšD ›
+ëüj‰êŽê s@‰ê c@
+žOêósOê¼ ˜D “GD‹ê ¹D Ÿˆê
+ ëúiOêº
+w@žw@G@Oê÷vÒO
+–÷ ž¾D ŸðDßø8ãëùhw@žw@W@Oê÷vŒê
+‡ê Oê¹ –¶D žóD_DŠê ‹ê ëøg3FžOê¸ƒê›Žê ›ŽêOêþvßøèâ –¶D žôDßøÜâãD3Fž ë÷kƒê
+žŒê Œê Oêüv‰ê Œê Oê· –¶DžòDâDßø¤â
+ëûj3Fžƒê žŒê Œê Oêüvˆê Œê Oê» –¶DžñDáD‡ê  ëúiŽê
+3FžOêº
+ƒê žŒê
+3Fžˆê ëùnOê¹ ƒê žŒê ›Œê Oêüvßø–´DžgDŠê ¸DŸŒê ëþhOê¾w@ž_@w@Oê÷vzO–÷›ž»DÜDßøܱ ëøl†ê
+žw@žw@Oê÷v‰ê‡êO긖³DžÚDWDŽê ‹ê ëüg†ê
+ žOê¼ E@Šê
+žŠê
+Oêúvßøˆ¡–²DF ›f@ÑDT@ËDßøt‘^@› ë÷k^@ ›Oêözˆê ~@Oê·]@›ÑDÎDßøP‘vD]@ßøDáOêõsŒêëûf“…ê žD›ðDßø(á¨DOê» \@›ëöe\@ ›Oêôx‡ê t@Oê¶X@›ÆDôD¤DX@ ëõd€ê
+
+›gDOêµDßøØÀZ@›ëô`2OZ@›Z@Oêòs†êb@Oê´ß“»D › Ÿ“D ëðb_@;FŸ{@
+›Oê°
+“êê
+› ŸñCõÝõæS3D ›uDëöe_@›_@›_@Oê÷sŸœD “dDFê ê ê
+ŸdDŽêOêþsEê “êêOêµCê ›ñCõÝõæS3D ›pDßødã
+›Œê Oêüsß “:DDêêëðb7@Oê´C›:DŸ@ê {@ Ÿƒê{@ÆOOêós“ ê
+˜ƒê
+C@˜C@Oêós“Dêê
+š@êŠê
+šŠê
+ê
+˜D›C@˜C@ƒê Oêós“Hêê
+Oêöp+N †fDëó`Bê>@Oê²&C œD
+˜€ê˜ œE@…ê OêõpCê
+ê
+˜‚ê B@…ê
+ˆê Œê S@šOêós“ñJCõÅõƒCV3D›0D
+k@k@Oêós“€ê {@Oê·ñJEŒêõÅV@õƒEV5,D #DœëòcO겄ê l@l@œMOêôte(D D˜ëóf€ê
+
+ ëõkŠê
+OêµG@g@Oê÷p{Oǘ:DyO’D š
+ëûj‰ê†ê B@˜‰ê Oê» B@…ê Oêòrˆê
+×;DmO™D›
+˜ ëúiOêº
+C@˜‹ê
+Žê C@˜C@ ˜Oêósß“>DaO°D žëùhOê¹ F@˜Šê Œê F@˜F@
+˜Oêöv÷=DWO®D ëønOê¸E@˜E@ ˜U@Oêõuï»D ŸÜDßø8± ëþlG@ ˜|@‰ê\@‡êOêôtF˜Oê¾£DÚDWDƒê
+›ëügŠê
+xOð @1h“›[h
+“››h “›Ûh“›i“›˜[i “››i“›Ûi“ø?<Bê"ø><BêBø=<Bêbºš“Oêò"‚ê°‚êpb˜
+›c@œ#@
+œ,@
+c@D›ŸDø<<ø; Cê
+cOê÷*
+ ›˜¢D
+œ#ê8@C@Oêr0šD›€ê²
+‚Dø8<ø7 Cê
+c@D
+›ø1Œë Dø4<ø3 Cê
+ê
+€ê¹Pê c@D›ë€Dø/<ø0 @ê ø.<@ê@ø-<@ê`Oêô#
+ê ‡ê¸W
+$ê
+¼Du@Oêp6¬D†ê°ˆêê†ê°V@}@.DáDø$\´Dø#lOêù'‡ê¹Eê%ø"lEêEø!lEêe‡êyf-º•ñ+EõâõöU5/"ê 
+ê 7Dl@Oê|5'D…꼃ê
+Œ‰êtiBêBø ŒBêbßø4ºD!’ë
+O’Dõb’à˜ªØ[ƒ¾…1$Ã} Uþ±Þ€§Ü›tñ›Áú
+Oêò,Šê
+Œê²ŒêrlšÔDh”Dš¼DdDãOêr<“Œê² Œê²\
+ðOêºHëƒ^ø@,OêùDˆêúSø@<„êyDˆêÚD„ê™$CDšD›Nø@LOêó.Žê³Žêsn›[hD›%DuD&ê @‰ê ›šMDOês4„계ê³T›C@@šê
+ê
+S@Oêy2D›‚ê¹k@‚ê¹Rê =@k@$­D3 ñ
+êS@Oêx2囜‚ê¸ƒê ‚ê¸Rê êc@$¬D›ë“« ñ“ð$«ë… ñ$ªðUø@ÌëƒSø@| ñ ðOê¼F냆êüOê÷BSø@LPø@<†êÜ‚êwB#D‚ê—"3DœDš@ø@< ñðOêò.Žê²ŽêrnšišD ˜DšsD @œ*êB@DšOêr0€ê²
+˜…ê³rD @…ê³UŠê
+˜RDˆê
+šDFšP`
+yº“Bê
+{º “OêœCBê
+}º
+“Bê"}›BêBÍ}› BêbCê‡E›º’º FêƒFBê€2› V@úCê‡3BêP"k@ÅV@:šEêW%F-Jk@…;šF,J@ë˜-
+˜@ë[Bë.š˜"ê
+Žê
+EëÒ’7šM~rAë“Fë“ê ~NCê#~CêCÍ~Cêc ºEê%ŽEêEÎ “›Eêe› (º• Cê‚N›˜EêƒF• › Eê€5Cê‚3u@ÖŽêOêÀ^FêP&.˜NêR.u@FÑHƒêë
+˜€F˜ˆê
+˜ê
+ë
+ƒF˜ ê
+-˜@ë ›“Eë“Oê›8‘ø!POê›N‘ø 0HêŠH‘ø%`NêŠ>ˆêOêË^Cê#‘ø"PNêZ.ˆêCêC‘ø#PCêc‘ø$Pº “OêšCEê%‘ø&`Cê‹3EêE‘ø'`EêeOêš6Fê‹F(ºOêÊU^@{KEê[%Ã†ê ˜yM@ë˜Në ›6ê Hë
+˜#ê
+'ê e@ƒêuLë ›Cê
+êFêX&ÃŒê ˜(N@똛Fë-žLë#ê
+Eë ‚˜Dë › ê ˜(ê
+ê
-Àø ë Àø°Dë Àø Àž›œÐøÐø Ðø°ÐøÀë ÀøFë
+‹ê
+Dë œ›
+›…ê
+Dë‘øE@ë
+›Cë $“‘øA
+$›.ê›ê
+
+ê@ë
+HëÓ*šIë%ê
+œ‹êœ
+ê
+'œ&@œ FœêœŠê à
+&šë
+œ‰ê
+ ˆêœë‘øiPNë ë
+Kë ë“Lë “‘øh0‘ømÀCê#‘øjPCêC‘økPCêc‘ølPºEê %‘ønÀEê E‘øoÀ“Oê›CCêŠ3Eê eOê›<LêŠL,ºOêš5%”Œê OêËSEê‹NOêšECêZ#Eê‹5Œê vKŽêOêÊ^ãœNê[."FrL…êBë&šœ*›Në, ê
+Lë#ê +›ê š…ê ê
+Žêä›EëOê~Cê›­Nê›Eê“›ŽêCê’UšŒêEêÒOêBlšŽê(LêÒšƒê ‚ê'š)U@šêš@š”F(š ê 'šˆê ë ‘F)š ê š…ê Në’šzAã“Gë‘øq@“‘øp0’=OCê#‘ør@CêC‘øs@‘øuPCêc‘øt@º“Dê$‘øvP›DêD‘øwPDêd ›"º&’šEêƒEOê“<›LêƒLœ ›Dêƒ4› Cê‚3še@ŒêOêÂ\šLêR,Ôšƒê &›DêR$še@L›Cë*› +œGë(Lë$ê š&êš
+Ꚍê
+Gžš=›BëFÀé c@›ëA›Kë
+Oê,EêežŽê Lêlö FêEfˆê Žê ž0•&ŒêÖ&žOêÖIžIêF9ö FêE6OêÅ&HêUxOêņêNêU~&‰êOê•Iê…i†ê•0Žê ë!LëëEëë•Fë*ž•*Oê•<+Lê…L­ Eê†N+¶ Oê•HFê…6*Œê +žHê…5ŽêOêÆ^*ž+NêV.öFêU&ˆêŒê Rø€lRø|\ëKëë žHë
+5F*ž%ê®F+.ê*ê +†ê ëêŽêJë u(ž2•Eë Oê|)ž3•2LêOê~(žNê)žOê†~(žNê–Oê†|)žˆêLê– OêFh(ž‰ê HêÖOêFi)žŽêIêÖžŒê €êžƒê (žê)ž ê ž
+ž‰ê
+ Në v30–žEë1–2žëEë –•
+žOêU
+NêÅ~OêU LêÅ|-
+Eêh6
+FêfŽêŒê žOêÖ
+žNêFnŒêÖ"ž…ê­žFë žë
+' žOêÕIFë IêE9OêÕL'LêE<OêÅ'HêUxOêÅŒê NêU~'‰êOê•Iê…iŒê•Žê ë•Fë  •01žOê•81Hê…HOê•>0Nê…N­ Eê†<0¶ Fê…6ˆê Žê1žOêÆ\0žLêV,OêÆX1žŽê HêV(Røxl…ꮬFRøt\Lë u žLë 0žë
+Në $ê 1ž'ê *ž5F0ž.@+‰ê¨F1êëžŒê •Në 6Oê~FêNêOê…~Nê•®ˆêFê•OêEh‰êHêÕOêEiŽêIêÕ(†ê …ê
+‰ê
+ Në ë Eë
+ë•Lë •OêU NêÅ~OêU  žLêÅ|-
+Eêh6
+FêfŽêŒê žOêÖ žNêFnŒêÖ#ž…ê­žFë ž­
+ž•Fë OêÕIIêE9OêÕLLêE<OêÅHêUxOêÅŒê NêU~‰êOê•Iê…iŒê•Žê ëOê›>•Fë 
+•Oêš<OêšENêŠHLê‹LOê›NEê‹5OêÊVNêŠ>Œê OêËUFê[&ˆêEêZ%Œê ŽêRéVdGë1Ÿd
+ê
+Eë*ëLë %ê +%ê
+0~@Ÿê Žêd”Lë-Eê?œGê¯Gê•­ŒêEê”OêDlœŽêLêÔOêDnœ‡ê NêÔ(œ…ê¤FœŒê )œ¦FœŽêœ ê œê(œ Fœê )œŒê ë  FœêœŽêGëë ˜Cë ë “Fë“›ž] ›EêÃu\›DêÃt
+Cê
+@ê`k@õ `@ œEêDe€êÔ$œk@œDë
+ê  ê1˜}@[ ê
+Cê
+@ê`k@õ `@ œEêDe€êÔ%œk@œDë
+›Dë
+œGêD7ä DêE4
+›Gêƒg„ê“}@ë“@ë “*›ž +›FêƒFœ *›+˜*DêƒD› Cê€3€ @ê…0s@î`@+œäDêU$+D@FêU&0^@Ré0ë1Eë
+Cê
+@ê`k@õ `@œEêDe€êÔ&œk@œDë
-Àø ë Àø°Dë ÀøÀ
-› œÐø Ðø$ Ðø(°Ðø,Àë bHë
-Àø$€ë Àø(°Dë Àø,À ž›œÐø0Ðø4 Ðø8°Ðø<Àë Àø0Fë
+Ré0ë *›Jë
+ë +œEë
-Àø4 ë Àø8°Dë Àø<À õ }®õ ~‘êôè­°½èðŸ
- Iÿ¸‘Sÿ´Ñäÿ¶€Jÿ¹¡}兩Þÿ¶äÿ¶…{視Ùÿ¶ |ïŠÈÞÿ¶•Fÿ·áÙÿ¶¥Hÿ¹Q{טּPÿ·áEÿºQqï«~ï«èòÿ±€!ùÍ·îÿ±uï®X×ÿ± cùÝÇòÿ±…îÿ±•aï±Ñ×ÿ±¥°ÿ °Iÿ¸‘Rÿ³Ñäÿµ€Jÿ¹¡}露Þÿµäÿµ…{視Ùÿµ |ï‹ÈÞÿµ•Eÿ¶áÙÿµ¥Hÿ¹A{טּWÿ¶áDÿºApï«~ï«èòÿ°€!ùÍÇîÿ°tï®H×ÿ° cùÝÇòÿ°…îÿ°•`ï°Ñ×ÿ°¥°ÿ ÀIÿ¸‘Qÿ²Ñäÿ´€Jÿ¹¡}Þÿ´äÿ´…{視Ùÿ´ |ïŒÈÞÿ´•DÿµáÙÿ´¥Hÿ¹1{טּVÿµáCÿº1wï«x~ï«èòÿ·€!ùÍ×îÿ·sï®8×ÿ· cùÝÇòÿ·…îÿ·•gï·Ñ×ÿ·¥°ÿ ÐIÿ¸‘Pÿ±Ñäÿ³€Jÿ¹¡}Þÿ³äÿ³…{視Ùÿ³ |ïÈÞÿ³•Cÿ´áÙÿ³¥Hÿ¹!{טּUÿ´áBÿº!vï«h~ï«èòÿ¶€!ùÍçîÿ¶rï®(×ÿ¶ cùÝÇòÿ¶…îÿ¶•fï¶Ñ×ÿ¶¥°ÿàIÿ¸‘Wÿ°Ñäÿ²€Jÿ¹¡}Þÿ²äÿ²…{視Ùÿ² |ïŽÈÞÿ²•Bÿ³áÙÿ²¥Hÿ¹{טּTÿ³áAÿºuï«X~ï«èòÿµ€!ùÍ÷îÿµqï®×ÿµ cùÝÇòÿµ…îÿµ•eïµÑ×ÿµ¥°ÿðIÿ¸‘Vÿ·Ñäÿ±€Jÿ¹¡}ï ¸Þÿ±äÿ±…{視Ùÿ± |ïÈÞÿ±•Aÿ²áÙÿ±¥Hÿ¹{טּSÿ²á@ÿºtï«H~ï«èOð ¼ñ íÿÞ€ÃÿÞ pï®úÿÞàíÿÞ…ðïBÈÃÿÞ¥Nÿøáÿÿü€Nÿúáøÿü 0ïnùÿüàÿÿü…øÿü¥øïJÈNÿøáòÿ´€0ïlîÿ´Nÿúá×ÿ´ 0ïncùÝÇòÿ´…îÿ´•dï´Ñ×ÿ´¥Iÿ¸‘Uÿ¶Ñäÿ°€Jÿ¹¡}笠Þÿ°äÿ°…{視Ùÿ° |ï€ÈÞÿ°•@ÿ±áÙÿ°¥Hÿ¹q{טּRÿ±áGÿºqsï«8~ï«èòÿ³€îÿ³wï®x×ÿ³ cùÝÇòÿ³…îÿ³•cï³Ñ×ÿ³¥Iÿ¸‘TÿµÑäÿ·€Jÿ¹¡}隸Þÿ·äÿ·…{視Ùÿ· |ïÈÞÿ·•Gÿ°áÙÿ·¥Hÿ¹a{טּQÿ°áFÿºarï«(~ï«èíÿЀÃÿРvï®húÿÐàíÿÐ…òïDÈÃÿÐ¥Nÿøáÿÿü€Nÿúáøÿü 2ïn(ùÿüàÿÿü…øÿü¥úïLÈNÿøáòÿ²€2ïl(îÿ²Nÿúá×ÿ² 2ïn(cùÝÇòÿ²…îÿ²•bï²Ñ×ÿ²¥Iÿ¸‘Sÿ´Ñäÿ¶€Jÿ¹¡}兩Þÿ¶äÿ¶…{視Ùÿ¶ |ï‚ÈÞÿ¶•Fÿ·áÙÿ¶¥Hÿ¹Q{טּPÿ·áEÿºQqï«~ï«èòÿ±€îÿ±uï®X×ÿ± cùÝÇòÿ±…îÿ±•aï±Ñ×ÿ±¥Iÿ¸‘Rÿ³Ñäÿµ€Jÿ¹¡}露Þÿµäÿµ…{視Ùÿµ |ïƒÈÞÿµ•Eÿ¶áÙÿµ¥Hÿ¹A{טּWÿ¶áDÿºApï«~ï«èíÿÒ€ÃÿÒ tï®HúÿÒàíÿÒ…ôïFÈÃÿÒ¥Nÿøáÿÿü€Nÿúáøÿü 4ïnHùÿüàÿÿü…øÿü¥üïNÈNÿøáòÿ°€4ïlHîÿ°Nÿúá×ÿ° 4ïnHcùÝÇòÿ°…îÿ°•`ï°Ñ×ÿ°¥Iÿ¸‘Qÿ²Ñäÿ´€Jÿ¹¡}Þÿ´äÿ´…{視Ùÿ´ |ï„ÈÞÿ´•DÿµáÙÿ´¥Hÿ¹1{טּVÿµáCÿº1wï«x~ï«èòÿ·€îÿ·sï®8×ÿ· cùÝÇòÿ·…îÿ·•gï·Ñ×ÿ·¥Iÿ¸‘Pÿ±Ñäÿ³€Jÿ¹¡}Þÿ³äÿ³…{視Ùÿ³ |ï…ÈÞÿ³•Cÿ´áÙÿ³¥Hÿ¹!{טּUÿ´áBÿº!vï«h~ï«èíÿÔ€ÃÿÔ rï®(úÿÔàíÿÔ…öïHÈÃÿÔ¥Nÿøáÿÿü€Nÿúáøÿü 6ïnhùÿüàÿÿü…øÿü¥þï@ÈNÿøáòÿ¶€6ïlhîÿ¶Nÿúá×ÿ¶ 6ïnhcùÝÇòÿ¶…îÿ¶•fï¶Ñ×ÿ¶¥Iÿ¸‘Wÿ°Ñäÿ²€Jÿ¹¡}Þÿ²äÿ²…{視Ùÿ² |ï†ÈÞÿ²•Bÿ³áÙÿ²¥Hÿ¹{טּTÿ³áAÿºuï«X~ï«èòÿµ€îÿµqï®×ÿµ cùÝÇòÿµ…îÿµ•eïµÑ×ÿµ¥Iÿ¸‘Vÿ·Ñäÿ±€Jÿ¹¡}ï ¸Þÿ±äÿ±…{視Ùÿ± |ï‡ÈÞÿ±•Aÿ²áÙÿ±¥Hÿ¹{טּSÿ²á@ÿºtï«H~ï«èíÿÖ€ÃÿÖ pï®úÿÖàíÿÖ…øïJÈÃÿÖ¥Nÿøáÿÿü€Nÿúáøÿü 8ïnˆùÿüàÿÿü…øÿü¥ðïBÈNÿøáòÿ´€8ïlˆîÿ´Nÿúá×ÿ´ 8ïnˆcùÝÇòÿ´…îÿ´•dï´Ñ×ÿ´¥Iÿ¸‘Uÿ¶Ñäÿ°€Jÿ¹¡}笠Þÿ°äÿ°…{視Ùÿ° |ïˆÈÞÿ°•@ÿ±áÙÿ°¥Hÿ¹q{טּRÿ±áGÿºqsï«8~ï«èòÿ³€îÿ³wï®x×ÿ³ cùÝÇòÿ³…îÿ³•cï³Ñ×ÿ³¥Iÿ¸‘TÿµÑäÿ·€Jÿ¹¡}隸Þÿ·äÿ·…{視Ùÿ· |ï‰ÈÞÿ·•Gÿ°áÙÿ·¥Hÿ¹a{טּQÿ°áFÿºarï«(~ï«èíÿØ€ÃÿØ vï®húÿØàíÿØ…úïLÈÃÿØ¥Nÿøáÿÿü€Nÿúáøÿü :ïn¨ùÿüàÿÿü…øÿü¥òïDÈNÿøáòÿ²€:ïl¨îÿ²Nÿúá×ÿ² :ïn¨cùÝÇòÿ²…îÿ²•bï²Ñ×ÿ²¥Iÿ¸‘Sÿ´Ñäÿ¶€Jÿ¹¡}兩Þÿ¶äÿ¶…{視Ùÿ¶ |ïŠÈÞÿ¶•Fÿ·áÙÿ¶¥Hÿ¹Q{טּPÿ·áEÿºQqï«~ï«èòÿ±€îÿ±uï®X×ÿ± cùÝÇòÿ±…îÿ±•aï±Ñ×ÿ±¥Iÿ¸‘Rÿ³Ñäÿµ€Jÿ¹¡}露Þÿµäÿµ…{視Ùÿµ |ï‹ÈÞÿµ•Eÿ¶áÙÿµ¥Hÿ¹A{טּWÿ¶áDÿºApï«~ï«èíÿÚ€ÃÿÚ tï®HúÿÚàíÿÚ…üïNÈÃÿÚ¥Nÿøáÿÿü€Nÿúáøÿü <ïnÈùÿüàÿÿü…øÿü¥ôïFÈNÿøáòÿ°€<ïlÈîÿ°Nÿúá×ÿ° <ïnÈcùÝÇòÿ°…îÿ°•`ï°Ñ×ÿ°¥Iÿ¸‘Qÿ²Ñäÿ´€Jÿ¹¡}Þÿ´äÿ´…{視Ùÿ´ |ïŒÈÞÿ´•DÿµáÙÿ´¥Hÿ¹1{טּVÿµáCÿº1wï«x~ï«èòÿ·€îÿ·sï®8×ÿ· cùÝÇòÿ·…îÿ·•gï·Ñ×ÿ·¥Iÿ¸‘Pÿ±Ñäÿ³€Jÿ¹¡}Þÿ³äÿ³…{視Ùÿ³ |ïÈÞÿ³•Cÿ´áÙÿ³¥Hÿ¹!{טּUÿ´áBÿº!vï«h~ï«èíÿÜ€ÃÿÜ rï®(úÿÜàíÿÜ…þï@ÈÃÿÜ¥Nÿøáÿÿü€Nÿúáøÿü >ïnèùÿüàÿÿü…øÿü¥öïHÈNÿøáòÿ¶€>ïlèîÿ¶Nÿúá×ÿ¶ >ïnècùÝÇòÿ¶…îÿ¶•fï¶Ñ×ÿ¶¥Iÿ¸‘Wÿ°Ñäÿ²€Jÿ¹¡}Þÿ²äÿ²…{視Ùÿ² |ïŽÈÞÿ²•Bÿ³áÙÿ²¥Hÿ¹{טּTÿ³áAÿºuï«X~ï«èòÿµ€îÿµqï®×ÿµ cùÝÇòÿµ…îÿµ•eïµÑ×ÿµ¥Iÿ¸‘Vÿ·Ñäÿ±€Jÿ¹¡}ï ¸Þÿ±äÿ±…{視Ùÿ± |ïÈÞÿ±•Aÿ²áÙÿ±¥Hÿ¹{טּSÿ²á@ÿºtï«H~ï«èôL«pï®Ðì‹pïèrïê(tïìHvïîhÀì ‘ê£õ s~ôx¯½ì‹pGSHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro@openssl.org>
-
- ô 0SâÀ ãÍ‚aôQnÆóÏÊaô
-bôöeùò`
-bô\Aó
-@HðòPaóô!@ó†¨òÖ!Bó‡N©ò¢.ªòD(ðòTA@ór!ót!ó&NàòA#ò1 òtó@Hðò& òÔADót
-
-ô"nâ/Jô
-òVáòÖ!BòÖaFòÖa
-ò0 ƒâBˆxò¨tòø€æòú æòh¨:òø…Úò@Èzòêhvòú¥ÚòÀèvòhˆ8óü€çòêHtóþ çòhÈ<òø…ÙòBÈ|òjH4òh¨:óü€æòú¥ÙòBÈtòhè>òø…Úò@è~òêhvóü æòhÈ<óþ€çòjh6òú¥Úò@Èvòèpòø…ÙòÂèpò ‚âjH4óü çòhè>óþ€æòêÈzòè(ròŽÀºóø…ÚòкóÀ2òlˆ8òÇôúÅ„òèè0óÐ
-ôô ƒâP
-ô-
-ôôð ƒâP
-ôô0 ƒâÀ`ƒâ-
-"ô-*"ôG"ô-
-ô-*ôGô¥! á`â Ñç2& á âèQå@$àì!å
-ó$ôtÁó'%ôôáóG&ôø!Fóg'ôRA@ó Dâð!Bò @EâðADò PFâòaFó `Gât
-BôèÈ&ò-Šôèˆ&ó-ÊôDÈ ò-ŠôD óÇôNH*òôN*ó-JôäH"ò-
-ôä"ó-JôFH"ò-
-ôF"óGôô".â`@ƒâPƒâ/
-"ô-*$ô-J%ôÄ!ºó-j$ô-Š%ôR¥¡òÈaºóTÅ¡òç$ôVáò÷%ôX%áòYgòàºóPihòP .òŒâòˆëò
-$ô-*$ôG$ô@ƒâ-j$ôÆ
-Bô… âò„êò‰ãòƒëòˆæò‚ìò‡çòíò†èò€éò'.â/êô„L¢ò H¬òH­òƒH£ò‚H¦òH§ò€H¨ò
--â/JBô‰ì¢òƒèªòˆè£ò‚è«ò‡è¦òè¬ò†è§ò€è­ò).â/ªôƒ¬¢ò‚¨£ò¨¦ò€¨§ò¨¬ò*.â/
-BôˆŒ¢ò‚ˆªò‡ˆ£òˆ«ò†ˆ¦ò€ˆ¬ò‡ âòêò†ãò€ëò -â/Jbô¥è¨ò¤è©ò¥ˆ§ò¤ˆ­ò¥æò¤ìò¤¨¨ò -â/êô†ì¢ò€èªò).â/êbô¥H®ò¥è£ò¤è«ò'.â/ªbô«ˆ©ò«íòªéò«è¬òªè­ò&.â/Êbô­ˆ¨ò­çò¬èò­è¦ò¬è§ò&.â/Šô#.â/Š"ô‰è¨ò¯è©ò‚,¢ò(£ò€(¦ò«(¨ò¤(§ò(¬ò(­òÌ¢ò€È£ò«È§ò¤È¦òªÈ¨ò€ ¢ò«¦òª§ò¯¨ò¤£ò
--â/*bô‡H¢ò†H£ò†¨¢ò¥¨£ò¥(¢ò­(£ò¬¢ò‰£ò­È¢ò¬È£ò%.â/*bô,â/jbô‡¨£ò¥¢ò­£ò†È¢ò!.â/j"ô¥È£ò -â/*bôˆ®ò*.â/Jbô­¨®ò&.â/Šbô¬(®òf¨pòfÈzò‰È®òú€¦òü æòHè>òØ…šòFÈ~òê(ròú¥ÚòÆèròH0óü€§òj¨:óþ çòHÈ<òØ…™òfÈ|òjH4òHˆ>óüà¦òú¥ÙòfÈtòÎpòÞåšòÆèpòê(róü æòNÈ<óþà§òêHtòú¥ÚòÆÈtòN(2ò ƒâÞå™ò`@ƒâfèrò ‚âjH4ó@„âü çòÎè0óþ
-"ô-*$ôB ó-*"ô-J$ôD("óðPƒâG"ôg$ôFH$ó-
-ô-*ôGô ƒâ`@ƒâPƒâÀ`ƒâ-
-"ô-*$ôBH óB ò-*"ô-j$ôFˆ"óF("òg"ô§$ôJÈ&óJh&ò-Jô-
-ô-Šô-*ôÇôgô
-$ô-*$ôG$ôNƒâ-j$ôÆ
-Bô… âò„êò‰ãòƒëòˆæò‚ìò‡çòíò†èò€éò'.â/êô„L¢ò H¬òH­òƒH£ò‚H¦òH§ò€H¨ò
--â/JBô‰ì¢òƒèªòˆè£ò‚è«ò‡è¦òè¬ò†è§ò€è­ò).â/ªôƒ¬¢ò‚¨£ò¨¦ò€¨§ò¨¬ò*.â/
-BôˆŒ¢ò‚ˆªò‡ˆ£òˆ«ò†ˆ¦ò€ˆ¬ò‡ âòêò†ãò€ëò -â/Jbô¥è¨ò¤è©ò¥ˆ§ò¤ˆ­ò¥æò¤ìò¤¨¨ò -â/êô†ì¢ò€èªò).â/êbô¥H®ò¥è£ò¤è«ò'.â/ªbô«ˆ©ò«íòªéò«è¬òªè­ò&.â/Êbô­ˆ¨ò­çò¬èò­è¦ò¬è§ò&.â/Šô#.â/Š"ô‰è¨ò¯è©ò‚,¢ò(£ò€(¦ò«(¨ò¤(§ò(¬ò(­òÌ¢ò€È£ò«È§ò¤È¦òªÈ¨ò€ ¢ò«¦òª§ò¯¨ò¤£ò
--â/*bô‡H¢ò†H£ò†¨¢ò¥¨£ò¥(¢ò­(£ò¬¢ò‰£ò­È¢ò¬È£ò%.â/*bô,â/jbô‡¨£ò¥¢ò­£ò†È¢ò!.â/j"ô¥È£ò -â/*bôˆ®ò*.â/Jbô­¨®ò&.â/Šbô¬(®òf¨pòfÈzò‰È®òú€¦òü æòHè>òØ…šòFÈ~òê(ròú¥ÚòÆèròH0óü€§òj¨:óþ çòHÈ<òØ…™òfÈ|òjH4òHˆ>óüà¦òú¥ÙòfÈtòÎpòÞåšòÆèpòê(róü æòNÈ<óþà§òêHtòú¥ÚòÆÈtòN(2ò.ƒâÞå™ò`@ƒâfèrò ‚âjH4ó@„âü çòÎè0óþ
-"ô-*$ô-J%ôÄ!ºó-j$ô-Š%ôR¥¡òÈaºóTÅ¡òç$ôVáò÷%ôX%áòYgòàºóPihòP .òŒâòˆëò
-"ô-*$ôB ò-*"ô-J$ôD("ò^ƒâG"ôg$ôFH$ò-
-ô-*ôGô0 ƒâ@ƒâ-
-$ô-*$ôG$ôNƒâ-j$ôÆ
-Bô… âò„êò‰ãòƒëòˆæò‚ìò‡çòíò†èò€éò'.â/êô„L¢ò H¬òH­òƒH£ò‚H¦òH§ò€H¨ò
--â/JBô‰ì¢òƒèªòˆè£ò‚è«ò‡è¦òè¬ò†è§ò€è­ò).â/ªôƒ¬¢ò‚¨£ò¨¦ò€¨§ò¨¬ò*.â/
-BôˆŒ¢ò‚ˆªò‡ˆ£òˆ«ò†ˆ¦ò€ˆ¬ò‡ âòêò†ãò€ëò -â/Jbô¥è¨ò¤è©ò¥ˆ§ò¤ˆ­ò¥æò¤ìò¤¨¨ò -â/êô†ì¢ò€èªò).â/êbô¥H®ò¥è£ò¤è«ò'.â/ªbô«ˆ©ò«íòªéò«è¬òªè­ò&.â/Êbô­ˆ¨ò­çò¬èò­è¦ò¬è§ò&.â/Šô#.â/Š"ô‰è¨ò¯è©ò‚,¢ò(£ò€(¦ò«(¨ò¤(§ò(¬ò(­òÌ¢ò€È£ò«È§ò¤È¦òªÈ¨ò€ ¢ò«¦òª§ò¯¨ò¤£ò
--â/*bô‡H¢ò†H£ò†¨¢ò¥¨£ò¥(¢ò­(£ò¬¢ò‰£ò­È¢ò¬È£ò%.â/*bô,â/jbô‡¨£ò¥¢ò­£ò†È¢ò!.â/j"ô¥È£ò -â/*bôˆ®ò*.â/Jbô­¨®ò&.â/Šbô¬(®òf¨pòfÈzò‰È®òú€¦òü æòHè>òØ…šòFÈ~òê(ròú¥ÚòÆèròH0óü€§òj¨:óþ çòHÈ<òØ…™òfÈ|òjH4òHˆ>óüà¦òú¥ÙòfÈtòÎpòÞåšòÆèpòê(róü æòNÈ<óþà§òêHtòú¥ÚòÆÈtòN(2òð ƒâÞå™ò@ƒâfèrò ‚âjH4ó@„âü çòÎè0óþ
-!ô-*!ôG!ô-
-ô-*ôGô
-P 
-P .ƒNƒ
-
-&ô-*&ôG&ô-
-ô-*ôGô
-nƒâ~ƒâŽƒâS
-ûòP)fòúòJDbódþò†„òòL¤bóÄbó&`øó)ò(€øó Ôøò ±ò
-ºò£È«ò0Ž€ò¢È¬ò¨ˆ ò…ˆ¡òˆ®òÇôˆ¯ò  ½ò£ˆ­ò0¾€ò†¨¤ò…¨¥ò„¨ªòиò¨«ò0΀ò£¨¬ò—ô©È ò†È¡ò§ôÈ®ò
-€»òȯò0ž€òÈ­ò‡ˆ¤ò†ˆ¥ò…ˆªò °¼ò„ˆ«ò0®€òˆ¬ò€¨ ò `G⇨¡ò¨®òàùò¨¯ò÷fô„¨­ò€èäò"¶ò©èåò
-pºò§èëò¸óg&ô¦èìò„h ò`†â‚h¡ò®@¿òkòh®ò °½ò®Ð¾ò
- ûòRaòæpòähpòF0óö`§òØaFòFh<òNÈ6òæpóÜ`æòRÁ òæ(rò¥˜sòLh6ó¹pçòØò§Xwò·•Äò§Xuò¥˜yò)H4òàºóÈ4ò`ˆâô‰8só`†âFôœ`æòR ò&¨:òâaºó
-ûòP)fòúòJDbódþò†„òòL¤bóÄbó&`øó)ò(€øó Ôøò ±ò
-ºò£È«ò0Ž€ò¢È¬ò¨ˆ ò…ˆ¡òˆ®òÇôˆ¯ò  ½ò£ˆ­ò0¾€ò†¨¤ò…¨¥ò„¨ªòиò¨«ò0΀ò£¨¬ò—ô©È ò†È¡ò§ôÈ®ò
-€»òȯò0ž€òÈ­ò‡ˆ¤ò†ˆ¥ò…ˆªò °¼ò„ˆ«ò0®€òˆ¬ò€¨ ò E⇨¡ò¨®òàùò¨¯ò÷bô„¨­ò€èäò"¶ò©èåò
-pºò§èëò¸óg"ô¦èìò„h ò ‚â‚h¡ò®@¿òkòh®ò °½ò®Ð¾ò
- ûòRaòæpòähpòF0óö`§òØaFòFh<òNÈ6òæpóÜ`æòRÁ òæ(rò¥˜sòLh6ó¹pçòØò§Xwò·•Äò§Xuò¥˜yò)H4òàºóÈ4ò †âô‰8só ‚âBôœ`æòR ò&¨:òâaºó
- ĉ@ʇ-
-"ô-*"ôG"ô-
-ô-*ôGô
-"ô-*"ôG"ô-
-ô-*ôGôâ
-°‹àK½ á°‹à˼ á ‚à‹ ‚à "‚àB½ á 0ƒà -Bàü á @„à‹<CàD½ á P…à MDàż á `†à‹\EàF½ á p‡à mFàǼ á €ˆà‹|GàH½ á ‰à Hàɼ á  Šà‹œIàJ½ á à ­JàÁ¼ á‹Aà-‚à#3 á„9ƒà¤F á…F„à¥Y áS…àˆl‡à¨s á‰y‡à©† á
-†ˆà*š á‰à €ä0€ä@€äP€ä`€äp€ä€€ä
-`ô-*`ôG`ô
-ô â/*ô0â/Jô`â/jôpâ/Šô€â/ªô@â/jAôPâ/ŠAôâ/ªAô â/ÊAô@
-!ô *!ô‹èàóp â/J"ôŠèáó` â/j"ô…èâóƒºó„èãó†èäóŠ²ó‚
-"ôÈäó *!ô â€è¤óŠè¢ó' ²óè£ó†è óÒ`˜ó‚¶ò8òòƒ·ò6Xæò¦Döò‹è¡ó§Dôò(ìò‡`ºó|GÇó0 â/J"ô|'Çó â/*"ôQg€ò â/
-"ô…èäó„èåóƒèâó‚èãó
-òbˆ8òð æóÜA@òØ
-òNHxò 0Câ¡
-0úò
-@ô *@ôG@ô
-Äë
-ë
-ol@j@Oê4—õÀwSø'p~@Âó…Sø'p~@Âó…'€7Âó…BSø'põ€r~@Sø"p†ê¦õàvSø&pÄó…@6Sø&`z@r@Äó…&À6Äó…DSø&`õ tSø$@r@b@ŒoÉoT@@ãoßø<7Êoe@¯{Db@õÀwOê2Sø'p~@Åó…Sø'p~@Åó…'€7Åó…ESø'põ€uSø%P~@n@•õàuSø%Pn@Âó…@5Sø%Pn@Âó…%À5Âó…BSø%Põ rSø" n@ oV@Jou@¯r@Oê2õÀwSø'p|@Åó…Sø'p|@Åó…'€7Åó…ESø'põ€u|@Sø%p„ê”õàtSø$pÂó…@4Sø$@}@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒnU@Ênl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ nV@Jnt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒmU@Êml@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ mV@Jmt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒlU@Êll@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ lV@Jlt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒkU@Êkl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ kV@Jkt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒjU@Êjl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ jV@Jjt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒiU@Êil@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ iV@Jit@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ÌhU@Šhl@j@Oê4—õÀwSø'p~@Âó…Sø'p~@Âó…'€7Âó…BSø'põ€r~@Sø"p†ê¦õàvSø&pÄó…@6Sø&`z@r@Äó…&À6Äó…DSø&`õ tSø$@r@b@ hIhT@¦Q@Oê1OêòõÀvSø&`n@Äó…Sø%pÄó…%€5Äó…Dõ€t~@Sø%pSø$@~@f@ŒõàtSø$@f@Áó…@4Sø$@f@Áó…$À4Áó…ASø$@õ qSø!0f@^@Oêö‚êVðU4„ê†êD„ê"ðÿT@…ê"‚ê”ð33Z@„ꃃêA‰²K@‚êAêð2ƒêQ@`C`𽺭
-ol@j@Oê4—õÀwSø'p~@Âó…Sø'p~@Âó…'€7Âó…BSø'põ€r~@Sø"p†ê¦õàvSø&pÄó…@6Sø&`z@r@Äó…&À6Äó…DSø&`õ tSø$@r@b@ŒoÉoT@@ãoßøü6Êoe@¯{Db@õÀwOê2Sø'p~@Åó…Sø'p~@Åó…'€7Åó…ESø'põ€uSø%P~@n@•õàuSø%Pn@Âó…@5Sø%Pn@Âó…%À5Âó…BSø%Põ rSø" n@ oV@Jou@¯r@Oê2õÀwSø'p|@Åó…Sø'p|@Åó…'€7Åó…ESø'põ€u|@Sø%p„ê”õàtSø$pÂó…@4Sø$@}@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒnU@Ênl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ nV@Jnt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒmU@Êml@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ mV@Jmt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒlU@Êll@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ lV@Jlt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒkU@Êkl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ kV@Jkt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒjU@Êjl@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ jV@Jjt@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ŒiU@Êil@§j@Oê2õÀwSø'p~@Äó…Sø'p~@Äó…'€7Äó…DSø'põ€tSø$@~@f@”õàtSø$@f@Âó…@4Sø$@f@Âó…$À4Âó…BSø$@õ rSø" f@ iV@Jit@§r@Oê2õÀwSø'p}@Äó…Sø'p}@Äó…'€7Äó…DSø'põ€tSø$@}@e@”õàtSø$@e@Âó…@4Sø$@e@Âó…$À4Âó…BSø$@õ rSø" e@ÌhU@Šhl@j@Oê4—õÀwSø'p~@Âó…Sø'p~@Âó…'€7Âó…BSø'põ€r~@Sø"p†ê¦õàvSø&pÄó…@6Sø&`z@r@Äó…&À6Äó…DSø&`õ tSø$@r@b@ hIhT@¦Q@Oê1OêòõÀv`Sø&`u@Äó…Sø&`u@Äó…&€6Äó…DSø&`õ€tu@Sø$`…êõàuSø%`Áó…@5Sø%Pt@l@Áó…%À5Áó…ASø%Põ qSø!l@„êOêóC`ð½ÜŸ
-
-
-±að4¿pG
-±að¿pGµF"¨ÿ÷öÿ˜½µ«Cø"Fÿ÷ìÿ½±>ð±¹pG@h>ð­¹@h>ðª¹8µOô¼q…hF(4õ€p>ð˜ùÕøx Bнè8@>ð˜¹8½Ã{Oð -éðO—° ðë’Óé
-w–•Oð
-‹ê
-Íé«ëŠÝé
-Cêv—/
-–’ —Ýé
-EÝé#"C+CØéE‚êƒê k纺`#ºB`*º‚`Ã`°½èðª‘
-‹ê Íé
-ÝøP°ê
- ë†Ýé
-OêGê|Oêw–Oð
-wˆê—'
-E&C/CÜéEt@}@dçšúŠó›ú‹ñ€è
-
-Úï(
-ÜO(Ü(Ô¿  pG pG pG pG@ö¢c˜BÜ°õ¨oÜ°õîÚ°õÈÚ°õšÚÌ(Üš(Ô¿  pG pG pG pG pG pG pG-éðC‹°œ™FFF"ˆFž!F¨ÿ÷¿ýJF F!F›˜GêÒ^¹3Fàà\®ù\A@ðø3t
-à h˜B ÐH@ò=IKxDyD{DõcTð_þTðqþA`d0Cðyú@±
-HOô¢r
+ê (ê k@)ê
+˜ž(ŸCê
+1“ë“Jë“›]›EêÃu\›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔ'œk@œDë
+œ ›Dë
+›$Dêœ-EꜥœEꔤu@Dê“^›|@FêÓ_›u@žGêÓ(›|@Ÿ^@)›ƒê›Ÿ@›ê(›ê )›Ÿ†ê ¦ê›ˆêEë2“›Cë
+3“ƒ“Jë“ ›˜ ž]›EêÃu\ ›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@œDë
+ F3œ›ê†ê@ë˜Cê
+)›˜Cë ë(“Fë)“!›!ž]›EêÃu\!›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@ œDë
+œDë
+ê†êEëë ”œDAë
+"›@ë ”˜"ž]›EêÃu\"›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@
+œDë
+Cê Oê‹tOêŠsDêšCê›l@OêKe{@OêJgEêÚGêÛl@{@(Ÿ*“}@Ÿê
+¼F)ŸŒê Ÿ ê ¾F(ŸêŸ…ê;F)Ÿ@*›Œê]›Dë›0“›CA1“s“@ë“#›]›˜#žEêÃu\#›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@  œDë
+)œ„ê œ%@œ ê (œê
+)œ…ê]›ê Œê@ë*˜2“›{A3“C*“Gë+“$›˜]›EêÃu\$›$žDêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@! œDë
+gž›Cë›ëGë ë#ê›Në #ê
+ê|@(› ê…ê%ž@ëë4“)›˜Cë 5“ë(“Ië)“%›]›EêÃu\%›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@ œDë
+Kë ë“Lë “&›&ž]›EêÃu\&›DêÃt
+Cê
+@ê`k@õ `@œEêDe€êÔœk@#œDë
+ ê
+3˜t@ëœ ê
+Cê
+@ê`k@õ `@œEêDe€êÔœk@$œDë
+ê|@
+Eêh6
+FêfŽêŒê žOêÖžNêFnŒêÖ ž…ê­žFë 'ž­ž'•%Fë OêÕIIêE9OêÕL%LêE<OêÅ%HêUxOêÅŒê NêU~%‰êOê•Iê…iŒê•'Žê *ê ë'•Fë •¥ ¾ Eê‡N¥ Fê„L¾ Eê‡5Fê„6ŽêOêÄ^ŒêOêÇ\NêW.LêT,…ê'†ê ¬FRø\ë ®FRø\Në4ë 5Nëë *•Fë+êê ‰ê ê*Žêë Oê|0•FëLêOê€|Oê~1•Lê“ Nê
+±jð¹pGµ"F ë
+#FÂøð0(Fÿ÷Üÿ `(ÿ÷Øÿ``ñ
+)‚êû²
+Óø°6ÂóKOê‹ Y@Þø0K@ÀóAë
+—ײÂó"9Oꇑ™Oê ™Oê‘™Oê‘™Oê‘™Oê‘ ™Oê‘
+™Oê ‘ ™ “ ›OêOêƒ
+‘ “Oê‚ “TÐ(D&DÖø°&«DÐø¨;¤D'D×ø°vS@Ûø¨/ƒêS@Üø°"ƒêšë
+Óø¨;"DÒø°fš^@Þø0*D^@›+DÓø¨?^@›#DÓø°2^@›+DÓø¨;_@Þø0{@Òø¨_@ ›#DÓø°2_@ F+DF ›Ñø¨ #DÓø°6C@Þø
+š+DÓø¨"D ›ôA+D“ø¨? CÙø K@Òø° šðADÔø°&ôCY@›ñ
+Ñø°Üø°ÎÞø°îÚø°ªê iŒê ÀóAëÑø¸Œê Åó!ëÅóEë…Ñø¸Õø¸QŒê 1OêkëÑø°êQiŽêÇóAëÑø¸ŽêÀó!ëÑø¸ŽêÁ²
+Šê
+‘iŠêÆóJëŠ
+Æó&ë†Úø¸¡ê
+Çó*ëŠ
+ÿ²Úø¸¥ê
+ë‡
+Úø°~_úŽúG@Ðix@Rø h@Öø¸Uh@Áó%•OêeÀóF•ÌóE•Àó%•Í²• ÁóA•ÎóE •Ìó%
+•Å²
+ë†Úø°Ûø°A@˜y@Öø¸qO@™ë€
+™ëÑø¸M@ ™ë
+ë Üø°A@ÐhH@ ™ëÑø¸H@™ëÞø¸H@ô曢D£D&D›øÚ@F ëCšøÚ9_@–øÚ9‡êaêA›#D“øÚ9ê!ÿ÷¬ü›ñ
+š"DƒêC’øÚƒê!ÿ÷rü›ñ
+±iðÕºpG
+±iðêºpG-éøOF
+†êQø `‹ê Úø`u@Úégs@|@¬çº$ºÀéC2›?º-ºÀé
+* OêBêrÙé…Dê tŠê‹êƒêj@±ç˜úˆòœúŒñº-ºÀé
+°½èð‡ø0S@îçbˆD4˜ø
+K {D<ðrû F°0½X"
+ÐKOô™rIH{Dö$3yDxDíçY`ñÄ
+K-{DÄøø0ÑK{DÄøü0äç
+JzDÃø¤ JzDÃø¨ JzDÃø¬ @"Ãø° ¼"Ãø´ pGüV
+JzDÃøÄ JzDÃøÈ JzDÃøÌ €"ÃøÐ Ø"ÃøÔ pG
+JzDÃøä JzDÃøè JzDÃøì €"Ãøð Ø"Ãøô pG
+JzDÃø! JzDÃø!JzDÃø !@"Ãø!p"Ãø!pG
+JzDÃø$! JzDÃø(!JzDÃø,!@"Ãø0!p"Ãø4!pG
+JzDÃød! JzDÃøh!JzDÃøl!@"Ãøp!\"Ãøt!pG$U
+JzDÃø„! JzDÃøˆ!JzDÃøŒ!@"Ãø!\"Ãø”!pG
+K{DÄø¨2 K{DÄø°2K{DÄø¸2K{DÄø¼2½ ˆR
+K{DÄøÐ2 K{DÄøØ2K{DÄøà2K{DÄøä2½ 0R
+K{DÄøø2 K{DÄø
+K{DÄø 3 K{DÄø(3K{DÄø03K{DÄø43½ €Q
+K{DÄøH3 K{DÄøP3K{DÄøX3K{DÄø\3½ (Q
+K{DÄøp3 K{DÄøx3K{DÄø€3K{DÄø„3½ ÐP
+KzD{Dõ<bÃø$&"Ãø(&Ãø,&
+XFEê …ê
+íEðl@ô÷Xþ@l@ÏçáÒë†ë
+ñF
+ëŠ ëÓ#Ýø€
+ë ø AFXF“r@ø ø ‚ê"ø ø ‚êBø ø ‚êb>ø "ý÷rþš)F(Fþ÷\û@F"YF¨ñý÷fþ±E›ÒÑ;©ë
+ ÊÑ"9F(F?ð¤ü
+
+
+Fð #DiBÉ
+K {D;ð:ùéç4F²
+
+¹@K#@<A
+ñ
+Ìçñ µØ1I °]øëÿ÷ª¾Oô¾sf"
+öçu F­o9Fÿ÷ÄýF ¹PFLFÿ÷åüëç hñ€E
+ÙJ D
+Ùe"D
+FE
+¿#hOðÿ0h½8µF Fÿ÷
+Kk"
I
-KxDyD{Dëç½7e
-JzDfpGÄ‘
-JzDÃø JzDÃø” JzDÃø˜ €"Ãøœ Ø"Ãø  pG
-JzDÃø° JzDÃø´ JzDÃø¸ €"Ãø¼ Ø"ÃøÀ pG
-JzDÃøÐ JzDÃøÔ JzDÃøØ @"ÃøÜ p"Ãøà pG
-JzDÃøð JzDÃøô JzDÃøø @"Ãøü p"Ãø
-JzDÃø0! JzDÃø4!JzDÃø8!@"Ãø<!\"Ãø@!pG”
-JzDÃøP! JzDÃøT!JzDÃøX!@"Ãø\!\"Ãø`!pG
-K„ø•"{DÄøœ2K{DÄø¤2K{DÄø¬2K{DÄø°2½
-K„øå"{DÄøì2K{DÄøô2K{DÄøü2K{DÄø
-KzD{DöÜÃøt%"Ãøx%Ãø|%
-ZCÒ²’8àšPFÍøÀ£šø J@ø ø ‚ê"ø ø ‚êBø ø ‚êc"ø0 ëÄF“þ÷‘þ¨ZFFô÷òì›QF"Fþ÷†þ<ÝøÀËѸñÇëКk“<FSÛ²“¾ç¨1F"=ðeø
-ài™ Õ@òG
-KA"{Díç”è
-ÕOô†s
-ëë
-FFRø{<xFCø F¹
-Ðà(F¡ü÷ÁûðÛ
-àhh
-`
-àá;QøléXŽBÐÙ p½:
-Ù_#
-I{DxDöøyDSðgúSðyú|½ÄN
-KA"{D8ð´ø à
-±Kh¹
-ãûEÝé
-Ð6AF0F*FWø?ÿ÷ÿIøÒç½èøƒ0µº¹0½ h:¤ûE€è0
-D`Eë Œh.F•h
-F3FàRø =0FCø F¹
-Ð#h:!úõSø"=)@Cø" Fþ÷gÿþ÷Šý!FF F½èp@ÿ÷Ž¿ p½8µFFÿ÷äþH±áh1± F!F*F½è8@ÿ÷}¿ 8½ðµ
-h
-h
-h`b
-Њh,š`ÐÊh<Ú`Ð13ëç½èðòg
-àYø êâX@2CIø åP3cEòÑ °½èð
- ê ãûgF` ë ‹hdFhãûENh¼E,¿¬Fñ Whê
-ê ¬E,¿
-ê ê æûEë (¿3Oðÿ:Oð
-ê ”hMh4¿
- ê (¿6Oðÿ:Oð
-ê ThÍh4¿
-ê ê Oðÿ:Oð
-ê çû‰hië (¿3
-ê ê æûEë (¿3Oðÿ:Oð
-Lhê [4¿
-ê ê Oð
-(¿6çû‰Wh
- ê (¿6ãû‰KihOðÿ:Oð
-Liê v4¿
-ê ê Oð
-(¿3çû‰i
-ê ê æûENhWiOðÿ:Oð
-ê æû‰h—ië (¿3
-ê ê æûEë (¿3Oðÿ:Oð
-Lhê [4¿
-ê ê Oð
-(¿6çû‰×h
-ê ê ãûEKi—hOðÿ:Oð
-ê ãû‰‹iWhë (¿6
- ê (¿6ãû‰ËihOðÿ:Oð
-Œiê v4¿
-ê ê Oð
-(¿3çû‰Wi
-ê ê æûEŽh—iOðÿ:Oð
-ê æû‰Nh×ië (¿3
-ê ê æûEë (¿3Oðÿ:Oð
-Ìhê [4¿
-ê ê Oð
-(¿6çû‰×h
- ê (¿6ãû‰Ëi—hOðÿ:Oð
-Œiê v4¿
-ê ê Oð
-(¿3çû‰×i
-ê ê æûEë (¿3Oðÿ:Oð
-Liê [4¿
- ê (¿6Oðÿ:Oð
-ê ”ii4¿
-ê ê (¿3Oð
- ê ãûgF` ë ‹hdFhãûENh¼E,¿¬Fñ Whê
-ê ¬E,¿
-ê ê æûEë (¿3Oðÿ:Oð
-ê ”hMh4¿
- ê (¿6Oðÿ:Oð
-ê ”hh4¿
-ê ê (¿3Oð
-š›“Oê‚ šë RBF ’RF “ ›þ÷œüë „F
-“FAF3FšÍøÀþ÷üÝøÀ#û
-š/à›JF ™ F
-™BF à šIFSF F
-šë
-ÿ÷5ú
-™ë
-š*њʹƹ¨
-šÿ÷/û+àëÅ’ª
-šÿ÷
-ÿ®
-‘OêCœžÜZ”[F °½èðOþ÷p¾š
-›’ë
-z’FQF*F›þ÷‘û›â ’„FYF"F[DÍøÀ“F ›þ÷ƒûÝøÀ#û
-š+Fÿ÷Pù;YF
-š+Fÿ÷Aù ›š™
-™0F
-™0F
-™ZFÿ÷,ú šQF
-™Íø
-ëê (¿6åû#ëê
-ê (¿6åû#
-ê (¿7åû#ëê
-ê (¿7åû#Ži
-ê (¿7åû#ëê
-ê (¿7åû#Îi
-ê (¿7åû#ëê
-ê (¿7åû#
-¨+¹)F2FSFÿ÷¿ÿà
-à9Fý÷¹ù
-FÝah*C C
-ê Úñ
-këK
-ê ê„ê
-ê
- ê ë
-Ië ¼ñ ÑÑ@FIF½èød)
- FQFü÷þþ
-¿
-ñÿ3Äø c`¼BÐ!F8Fü÷%ÿ¿$
-Ÿ*ÝKh“BÑÖø™E$Ð8Fý÷òû8Fý÷'üF¹
-ÙOôàs
-ÚH#
-àYøÀëØøpñÿ>,ú
-ûGê Èøp ú÷_P¾ñ
-ûùñ
-Ú#
-±Cø% ch¹ã` ½èþƒ
- Ôø
-’à
- ™0FÛø Ëh ñS@ó`ü÷­ú
-›¹
-ñÿ:‘ëŠ
- ’“’{àÚø
-šÍé˜
-™› ûÍéûZø 
-àë
-à(F)Fÿ÷€ÿ
-à F!Fÿ÷kÿð±(F)Fÿ÷fÿȱ7+F%FF#F,FFkh
-ý8¹9H¨"9I9KxDyD{Díçæ`(Ff`û÷°ÿF8¹4H­"4I5KxDyD{DÞç(Ñ ø½‡BØ0H³"0I1KxDyD{DÐç F1Fÿ÷ÿ¹
-ÿ÷´ú
-HFÇø  )F:F#Fþ÷þ
-Ñ@òS
-ú ú™FJð
-3à#Oð
-ªD#û
-#(F!F*FèX
-à2F'àQhKBø?¹7§B÷Ñ
-ÛÈÿ÷n¾
-Ðkh±+hhð
-ëƒÓøÌ:^Câhch"±;±#hhÛCà#±#hhàOðÿ3jh
-±*hhð(FB)F"F;F¿vBÿ÷"ú(±#FÄø ,FF²çoð8Fü÷Öù0F½èü‡
-Ûò#
+H{Dö CyDxD[ðTþ[ðfþ Ôç d
+FFÿ÷ªùÀ½Bhµ¹±úð@ ½h# hH@šBÜ°ú€ðôçTø#3Cõç0µ‰°¬F F‘ÿ÷µû«!F“(F›
+K {D:ðœü F°½
+±Kh#¹
+Ð5Xø?2FIF(Fÿ÷ÿGøÒç½èøƒðµR±2ðF F
+ë
+oð@F-
+ëOð
+Ú"F)F0Fÿ÷àÿ¹
+Ú*F!F0Fÿ÷[ÿ¹
+Ø KOôØr I H{DönCyDxDéç0F
+Fÿ÷Ÿÿ°]øûøµFFFþ÷büp¹
+h
+œF‰FF ˜
+ñ+
+Ù~KOô¬r}I~H{Dö§CyDxDìçñ+
+ÙyK@òYyIyH{Dö§CyDxDÝç,ÑZêÑ °½èðOÿ÷å¼,Ü£ë
+
+“Oê‹•HF“š›D“Êñ
+ë šÿ÷Šü›š KD•“›
+›ÿ÷zü ›»ñƒê
+“¨DPÑZêMÑšIF(Fÿ÷‹üš8F™ÿ÷†ü š™
+˜ÿ÷ü#F
+š9FHFþ÷þ#FF*FIF@Fþ÷ÿ#F¦ë
+*FIF(Fþ÷þ
+*F
+ê
+›Šê;DF#FFþ÷êýë d
+˜ÿ÷öþžçWø#`
+Ü•K@ò½”I•H{Dö¸CyDxDìç
+ÜKOôßrIH{Dö¸CyDxDÝç£3+
+ÙŒK@ò¿‹IŒH{Dö¸CyDxDÎç-OêE Ü«*
+ë“+—
+“ ›
+˜D š“s
+› û9YÑFQF8Fÿ÷cû š@F ™ÿ÷^û"F™˜
+š8FÍø“
+Ýöä¨Íø–
+¤ë
+–
+¤ë
+–
+Oð
+Lë²(¿
ñ
-ü÷Wø(¹8F9Fÿ÷EúP¹Ùç8F9FBFü÷Äû
-0FQFÿ÷æþ
+ëLë i h(¿
ñ
-ü÷1ø(¹ F!Fÿ÷úP¹³ç F!FBFü÷žû
-(FQFÿ÷Àþ
-à F!F:Fü÷qû
-ܸñY ܸñÔ¿%%à%à%
-”ûñzÓ’ “
-àû÷xøšF›¨þ÷û
-Fþ÷'ú
-AF˜ ñÿ9ÿ÷(üñÿ8
-ݬFF
-ÿ÷üÉë‚D«BèÛ
-
-
-úÍø âFà Fû÷ôüFÉø
+
ñ
-›šEçÛÇç(Fú÷Aÿ
-àú÷€þ2FF#F(Fþ÷ù
- ú
-ûšFKð 3à#Oð
-›Fš“BÛ¹ñ
-
-Oð
-à™(F:F3F
-¨ú÷´üóh———«±@F1Fú÷
-ú®Íø  âFà(Fû÷Üú°`
+ëGëaMi h(¿
ñ
-›šEëÛÐç ñÿ6Oð XF1Fÿ÷°øX»¹ñ
- ú
-üÂFLð ñàOð Oð
-àF¸EßÛáçOêl 2ª
-
-ë
-³ÔOð
-¨ú÷Úû F3°½èð-éðGFFF‘FFû÷ú¾BÐNEÑ(Fû÷FúF
-ÐK#
-à(F
-Ðj+F:F G
- ñ8
-Ðj
-
-¾”½è0@ÿ÷ò¾i ±ÿ÷˜¾ÿ÷f¿
-Ñ@ò#
-žZÑÐø€àñ
-F Fÿ÷–ÿF˜¹­# `
-à#h FIF2FÝiCF¨G
-
-bp ¢pãp›#q
-bq ¢qãq|½-éðGF
-
-C
-ë ey Bê
-)qjp ªpêp
-
-jq
- ªq
-êq5
-ø6
-9q{p »pûp
-{q »q ûq
- p!qcp
-àpcq £qáqÁà§yUF”ø€^Fay?Bêh"yGê'
-ë ‘CâyGêgAà²xpx1x–øÀBê
-CñxBêa2y‘‘qyLê,FLê òy6Lêl
-…ø€jq: ?Ýø€ªqïq5ÝøÀ
-ë ©ñ ¹ñØßè ð * ø,;*
-ø,;ø\;2ø,;2 ø,;2
-ø,;ølOê#„ø
-„ø€cq; ?£qçq°½èðµF(0
-#qap ¡pâp
-bq ¢qãqþ½-é÷O’FhF‰FPhƒBÓ®hÀë
-ë
-ë Cêb£yCê
-+qip ©pép
-iq ©qéq5Ýø
-ø5 
-3qqp ±pñp
-qq ±qñq
-"p#qap ¡pâp
-bq ¢qãqÀà§y
-…ø€kq; ?Ýø€«qïq5ŸÝø
-ë ©ñ ¹ñØßè ð * ø,;*
-ø,;ø\;2ø,;2 ø,;2
-ø,;ølOê#„ø
-„ø€cq; ?£qçq°½èð0µ…°„hñ€
-Ka"
-H
-I{DxDõysyDLðÖûLðèû ±h˜G Fÿ÷Ôÿ ½ê
-CLðíúLðÿú#h FÛh˜G |½
-ø0ÿ÷^ÿ³¨IFRFÿ÷®ÿ豨©"ÿ÷¨ÿ¸±§B¨Ø1F
-à©
-™ šÿ÷ÿ¹
-
-±Ch`pGpµFFFQ±Z±
-à’
-H!F*FxD
-à8FñL÷÷êÿ
-kF‹°FF3k
-¹-à
-˜QFø÷1ù
-˜QFø÷ÿø¿%
-à÷÷ü›9F
-ŸRF¸G
-ñ,—ñl˜9F —÷÷.ý »@F!F
-ñ+FÈG
-ñ
-ñ FaF2F›Íø Àø÷×ùÝø À
-ñ+FÈG
-ñ+FÈG
-񛟸G
-QFÈG
-àHFñªn#Fù÷²þ
-
-à F÷÷£úòç F÷÷ŸúòçOð
-—ö÷¾ÿÐñ
-™8F —ö÷¡ÿÐñ
-(»@à0F)Fš#F Ÿ¸G
-Ÿ³ Ÿ‡± ñ,
-þF¹ñ
-ÿ¿% Fö÷,þ Fö÷sý0Fþ÷Dù
-
-WF
-á›
-“&àñlõ÷Ìÿ
+Oð
+Oð
+Lë²(¿
ñ
-ñàØø
-ñÿ:¨ñ©ñ !à#h F
-1à#h ñ,
- F1FRFÓøÀ+FàG(³#h ñ
-FÓøÀ3FàGб#h F
-FÓøÀ3FàG(±PF™õ÷òþ
-
-³›[h “˹@ò%
-(F2ðü (F2ðŒü(F2ðˆüF˜±
-™!³ š³›³ÿ±ßø`%
-Oð
-
-àOð
-àOð
-àOð
-àOð
- ˜Oê‹
-›ÝøàƒE’8¿™Oð(¿žCø+ 
-ñÿ38¿húóžDÖø€Íøà¸ñ
-øOð
+ëLëMiLh(¿
ñ
-OêH hÈñ
-ЙBÐAEЬ#
+Oð
ñ
-
-à˜ý÷÷üKø à±
+ëLëi h(¿
ñ
-Ýø(àZF^ø0;:úóîÐ ñ ˜EáÑ®²B Ð@òe
-˜Oê‰ Pø)0+ ØàWø)0 ™hþ÷Žÿ
-àWø 0
-ñÿ2
+
ñ
+ëGë†aÎi h(¿
+ñ
+Oð
+Oð
+•Lë¤bF(¿
+ñ
+ëGëÎi¤Êh(¿
+ñ
+
+ñ
+ë‚bGë
+idÎi(¿
+ñ
+
+Oð
+ë Në¤(¿
+ñ
+ëcGëŠidÎi(¿
+ñ
+¦ûg
+Oð
+ë Në¤(¿
+ñ
+ëaGëŠhdÎh(¿
+ñ
+¦ûg
+†ê“Šê “4@Ýé#
+ê [Oê2Cë KOê0ë
+ Fý÷[ù Fý÷’ùF8¹
+¹ 8½¹á`a`ùçhFý÷CûF
+ù€F4¹
+ FQFü÷ü
+F1Fÿ÷°þççµF
+‰EØñ€C;^ø#0#úòFø$ à*Fú÷_ý:F
+üLê HøÏÝç-éðCF•°0™F FFü÷JûÄD"äF
+0FOð
+“›ñ€A9Rø!0Oê
+éh“›+¿RD
+™3‘DÍ
+ñ“
+“ë‰ ›“ ›
+š“B1Ü Fü÷%ú›s± š!FFÛø Pÿ÷æþ
+ñÿ:ë Òš
+ñÿ:ü÷žÿ ±Øø
+›3
+“tç
+FF
+ñ
+#Fÿ÷>ÿ#F:hñÿ1(hÿ÷7ÿ›šE¬Ñ0Fü÷Iù€¹(Fü÷Eù`¹Km"IH{Dö SyDxDÕçOð
+çç)h
+Vø#P3RøœB@ê
+F©ÿ÷ÿ8±š!F Fÿ÷û
+‘-¹™XFû÷Þÿ
+š`¶#
+š#`Æ#
+€F
+šJó
+#h
+QFh:ðû QF˜
+š#`Oôžs
+Úf`"h
+ÑOôªse"
+ñÿ:ßç F­ù÷Eý(F(¿#€F“Oê‰1FF(F“ø÷Mý¸ñÙÝøÔ4 ®*F)F0FOðD
+I H{DöQSyDxD-çp
+KOô:r I
+H{DöQSyDxDWðÁøWðÓø3F"F(F½èp@Óæ
+ÙÍé
+ÛÐé
+ñÿ; ú ûÙEÔÚ0Fû÷šúFJø)
+ë‰
-™Qø 0;:úóæÐÔçš‘E¸Ñ˜*F™#Fÿ÷sý
-Fþ÷.þ
-0
-F^ø#0ÿ÷ãù
-ñÿ:ºñ
- Fö÷…ø0Fý÷Vü
-˜2ð,ú ˜2ð)ú›;¹ à™Qø$
-—V@‘ø2pÝø$ ‘ø1€Ýø(°TD?¤‘ø0`Gê(‘ø6pOêtT‘ø5ÀHê‘ø3€ZD‘ø9 ?‘ø=°Fêh…ê&@Gê '^@‘ø:À’‘ø4`Oêr2CD>C‘ø7pOê LLê
-,‘ø< Fêg„ê@n@훑ø8`OêssLê‘ø;ÀFê l‚ê@f@dD­‘ø>`Oêue6Fê &Ýø
-
-‘ø?`@1Jêfƒê
-ê
-
-Šê
-’TD…ê
-OêtTê
-
-Šê
-RDßø¸£Oêr2ÚDDê ê SDê
-Kê
-
-Ýø°SDßø˜£OêssÚDBê ê UDê
-Kê
-
-Cê UDßøt£OêõeÊDê TDê
-Kê
-
-Eê TDßøX£OêôTÂDê RDê
-Kê
-
-Ýø°RDßø8£OêòBÚDDê ê SDê
-Kê
-
-Ýø°SDßø£OêssÚDBê ê UDê
-Kê
-
-Ýø °UDßøô¢OêõeÚDCê ê TDê
-Kê
-
-Eê TDßøÔ¢OêôTºDê RDê
-Kê
-
-Ýø°RDßø´¢OêòBÚDDê ê SDê
-Kê
-
-Ýø°SDßø”¢OêssÚDBê ê UDê
-Kê
-
-Ýø$°UDßøp¢OêõeÚDCê ê TDê
-Kê
+ ú
+ù¢FIð 4›£BÝ¥BíÚ»ñ
+¡FÒç»ñ
+Ð%K@òÕ"%I%H{DögSyDxDèç3FBF9F˜ý÷§þ¿$:çOêi («
+ñ
+Oð
+Mç›™E·ÚOêi («8Fë‰ Yø€ú÷Tý
+ËF;úó“›»BÕÝ0Fû÷&ùJø±
+úú˜FJð
+3ššBìÜ»ñ
+4«
+(FKFZø€,ÿ÷?ù
+Oð
+ýFˆ±;F*FIFHFý÷ßÿFH±
+úô»@“OêJš“B¬¿ã£›
+­ø÷Tþ
+”늓 “(F“ “#š™”ÍøD Íø0 ““ý÷ üF
+ÛgK@ò?BgIgH{DöwSyDxDâç ñ<›šIF@Fý÷ÁþF
+©š˜ý÷û¿$cà›BFAF(F
+Û~#k"
+ñ
+ú÷Cüp»9F8Fþ÷/ý
+ñ
+QF Fÿ÷+ø
+±2hhð1FB0F;F"F¿mBý÷ÿx±#FÄø €4FF·çFÜç
+Šê
+Oê
+`î÷âùŠê!ð
-Eê TDßøP¢OêôTâDê RDê
-Kê
+Oê
+pî÷ÓùŠêF@ê
+ˆî÷Êù
+K{D™ç1F Fù÷Ìýñ
+
+
+
+Òq‹BÒ«BЂ#s"
+œô€c ÐÜø P#F:F¨G
+ñ8
+WDÁDÆø
+Ój+Fñ8aF0F G
+8F7D2Fö÷®þÍø
+ÚOôßs
+ŸsÑi#h
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+DƒB’ø„%p÷ÑpGXY
+bp ¢pãp›#q
+bq ¢qãq°0½-éøCFhFˆFUhBØÐø]
+ˆFF“«“›ñÛ+
+™Gê'šxGêGÚxGêgZy—Iê)šyÛyIêI
+ ««ëñ*ØOêÚšOêÈ×oðû¢
+™Dø<ºñ
+ðš—•“‘Cyx7ø,ø “Bê"øBêBøBêaø,M@™•Bê
+øLø,* ø,*ø,"
+ø," ø,"ø,ç ñÿ9ø, ñÿ9Cê#ø, ñÿ9Cø, ñÿ9ø ñÿ9BêBø ñÿ9Bê"ø\@¨”
+C™U@"•ì÷/þ›œø8P+
+<q{p+ »p+ûp#
+{q# »q#ûq+
+5p4qsp+ -³p#
+õpsq# $³qôq °½èð
+øLø,* -ø,"
+ø\Fø," $ø,øL\F®æ# ñÿ8ˆø
+ñÿ8ˆø
+ñÿ8ˆø
+#qap ¡pâp
+bq ¢qãq°ð½ÿ÷}ýêç-é÷OFhF‰FUhB؇h]
+õ€{3i ëë
+™Ú
+ûOê ëºñ
+™Gê'šxGêGÚxGêgZyIê)šyÛyIêIšIêi›Íéyÿ÷úü›]@›\@›CD˜Fºñ
+ªëñ+Ø›š™OêÓOêÈ×oðû
+øLø<+ ø<+ø<#
+ø<# ø<#ø<Ÿç ñÿ9ø, ñÿ9Cê#ø, ñÿ9Cø, ñÿ9ø ñÿ9BêBø ñÿ9Bê"ø\@¨›”
+C™U@š•ÿ÷øûÝéT›ø8P+
+<q{p+ »p+ûp#
+{q# »q#ûq+
+5p4qsp+ -³p#
+õpsq# $³qôq °½èð
+øLø<+ -ø<#
+ø\]Fø<# $ø<øLTF®æ# ñÿ8ˆø
+ñÿ8ˆø
+ñÿ8ˆø
+Ka"
+I H{Dò„cyDxDTðûøTð ù ±h˜G Fÿ÷Ôÿ ½
+ø0ÿ÷Xÿ@³RFIF Fÿ÷ªÿ³"YF Fÿ÷¤ÿà±EE
+™ÿ÷ÿ8¹
+
+
+
+
+
+
+
+
+±Ch`pGpµFFFQ±Z±
+
+ý½8µF Fÿ÷ÿ
+
+
+
+
+YFÿ÷áÿ:FQF Fÿ÷Ûÿ›¨F7F«± ±2F)F Fÿ÷Ðÿ¹ I°½èðñDñD Fÿ÷Äÿ°ú€ð@ ñç#hÓøÛi“›k¹ ñÜRFAF F›˜GCF ñ*FAF FÈG›[¹&¯ZF9F F›˜G;F¯2F9F FÈG:FAF Fÿ÷˜ÿ
+RFQF FÈG*FEFSF© FÈG›D6c¹ ñ˜[FBFAF FÈG2F>FCF© FÈG2F)F«çµLI|DòLpyD;ð¼ÿñ@
+
+
+üZFYFSF Fÿ÷ü[F õÜ{šYF FŸ¸GZF™ F°GCFBF õþx FAFÿ÷ðûCFBFAF Fÿ÷êûCFBFQF Fÿ÷äûšSF FFÿ÷íûKF*FIF Fÿ÷Øû› Fš™ÿ÷Òûš F™°GšKF FFÿ÷×û›BF™ Fÿ÷Ñû+F*F)F Fÿ÷¼û*F)F F°G›ZF FžF°G+F*F)F Fÿ÷¬û+Fš FFÿ÷µû õ}½èð ñ¨ ñì YF õ˜x°GšIF Fn­°GJFAF F°G]«šF“ F°GKFRF)F Fÿ÷…û*F)F F õþz°G*F)F[F Fÿ÷ˆû*F)FCF Fÿ÷‚û+F*F)F Fÿ÷mûšQF F°GSFñ8QF FŸ¸G[FRFQF Fÿ÷\û[FRFQF Fÿ÷Vû[FRFQF Fÿ÷PûRF™ F°Gš+F FFÿ÷Uûš+F FFÿ÷Oû› Fš™ÿ÷:ûš FF°GšKF FFÿ÷?ûš F›Fÿ÷9ûCFBFAF Fÿ÷$ûCFBFAF Fÿ÷ûCFBFAF Fÿ÷û*F›™ Fÿ÷!ûšSF FF¨GCF^çšB-éðO­ò¼MF’F‘“Ñÿ÷¯þ ò¼M½èðh õ€yQ¯s® õxiÛi“ñˆF“ÿ÷û› Fñˆ YFÿ÷
+‘ F¨G1F[Fš Fÿ÷Ëú2F1F F›˜G2F1FKF Fÿ÷Ïú;F2F1F Fÿ÷Éú;FZFAF F¨G
+ñDBF “AF F¦¯¨G•©KFš F ‘¨G
+›9F š Fÿ÷°ú9F Fÿ÷»ú3F ·®:F/© F¨G1FKFš F¨G› FD3
+“3FÈ®
+š1F¨G2FÙ®CF1F Fÿ÷ú3F2F1F Fÿ÷{ú1F Fÿ÷•ú ›CÑ›+±›±RF™ Fkçê®;F:F1F F õ{xÿ÷cú2F1F F›˜G3F:FAF õ†g F õYy¨G3Fbª ®9F F¨GJF1F F›˜GCF2F1F Fÿ÷Sú;F2F1F Fÿ÷Mú;F2F1F Fÿ÷Gú:F¯3F9F Fÿ÷@úKF:F9F F¨GCF òtH„ªAF F¨GCF:F9F Fÿ÷.úCF:F9F Fÿ÷(ú›1Fš F/­
+›9Fš F
+$@Fÿ÷>ý ûóâë ÕSDBF(Fÿ÷¸þ4 ,ñÑñ
+_úŠó“ô÷åÿ›ñ8 ñ|
+›ƒê
+î÷Çú)F Fî÷²ú"F)F F&ì÷ƒÿ!F@Fî÷‰ú!F Fî÷¤ú!F Fî÷ úBF!F Fì÷rÿ!FHFî÷xú!F Fî÷“ú!F Fî÷ú!F Fî÷‹ú!F Fî÷‡úJF!F Fì÷Yÿ!FPFî÷_ú!F Fî÷zú>ùÑRF!F F õ€{&ì÷Gÿ!FXFî÷Mú!F Fî÷hú>ùÑZF!F FH®ì÷7ÿ!F0Fî÷=ú #!F F“î÷Vú›;÷Ñ!FP¨î÷0ú*F!F Fì÷!ÿÀ#!F F“î÷Dú›;÷Ñ «2FFP©“ì÷ÿ›"FF’“î÷2úš›:õÑZFFFì÷
+YFXFì÷îþYFXFî÷úºñ
+øÑJFYFXFì÷âþYFXFî÷úYFXFî÷úBFYFXF ñ@ì÷ÓþYFXFî÷øùYFXFî÷ôù*FYFXFì÷Æþ"FYF@Fì÷ÁþAF(Fî÷æù'J)F(FzDõ3bì÷µþ›ã±0F™î÷éùP¬*F1Fì÷ªþ1F Fî÷Òùš !ö÷TüP¹OôÏc"
+ÐÄiÍi¬B Ñ,¹h hšBÑ0¼Ãç
+ÐÄiÍi¬B Ñ,¹h hšBÑ0¼°ç
+Ÿ¹?±´ú„ò·ú‡óR [ šB Ð@òƒ3C"
+K{Dëç-±)h Fÿ÷Óþ
+K
+þ÷)þ;FšQF Fþ÷#þ Fþ÷>ÿFH¹æ#A"
+K{D¹ç%[çEÉ
+
+
+
+ñ$
+Òi#d"
+ü øçá¿
+p0½-éðO­òÜ}‘FF
+#SFeJ
+˜zD8Cöd2ó÷lü›
+“’_Fì÷ŠÿAFHFì÷†ÿ
+›šFFì÷€ÿÓç®.©0F­ì÷yÿ¬6©(Fì÷tÿ>© Fì÷pÿ1F˜ì÷Žÿ›)FñD
+ó÷“û€
+ñ@ë
+
+ñ 3DHF“KFì÷Iþjç
+ ñÌ Ù@7D+«¸ñ
+8«“F™ Fÿ÷’ýRFIF F õ=zþ÷½ù õRÍø
+­\š[™(Fü÷ý
+@«“9F Fÿ÷„ÿ
+Ñö›DКIF@Fÿ÷Øþ
+” œ%D‹ê4@„ê %DøLOêu5Dê $øÌDê DøÌDê døÌ ”
+œ£D‡ê,@|@£DøLOê{{Dê $øÌDê DøÌDê d ” œøÌøœ'D†êê ø ìt@øŒ'DøLOêwgø¬˜Dê $øÌDê DøÌDê døÌ ” œHê (øÌ&D…ê <@l@Hê H&DøLOêvVøÌIê)øLHê hIêIø LIêi œ%D‹ê4@„ê ËD%Dø LOêu5†ê Nê.ø
+LNêNø LNên‡ê,@|@wD£DOê{t
+,ø¬Lê
+Lø¬Lê
+l…ê
-Ýø °RDßø0¢OêòBÚDDê ê SDê
-Kê
+ê
+Šê
+eDVD„ê
+OêvV
+ê
+Šê
+êUDGê
+Oêu5
+ê
+Jê
+\DWDOêttFê
+ê
+ê
+Jê
+ê WD
+Oê÷gVDEê
+˜
+ê
+Jê
+ê VD ë
+OêöVUDDê
-Ýø°SDßø¢OêssÚDBê ê UDê
-Kê
+ê
+‘DJê
+ê UD
+OêõETDGê
+˜
+ê
+Jê
+ê TD
+OêttWDFê
+ ˜
+ê
+Jê
+ê WD
+Oê÷gVDEê
+˜
+ê
+Jê
+ê VDë
+OêöVUDDê
-Ýø(°UDßøì¡OêõeÚDCê ê TDê
-Kê
+ê
+–DJê
+ê UD
+OêõETDGê
+˜
+ê
+Jê
+ê TD
+OêttWDFê
+ ˜
+ê
+Jê
+ê WD
+Oê÷gVDEê
+˜
+ê
+Jê
+ê VDë
+OêöVUDDê
-Eê TDßøÌ¡OêôT²Dê RDê
-Kê
+ê
+DJê
+ê UD
+OêõETDGê
+ ˜
+ê
+Jê
+ê TD
+OêttWDFê
+ ˜
+ê
+Jê
+ê WD
+Oê÷gVDEê
+˜
+ê
+Jê
+ê VD ë
+OêöVUDDê
-Ýø
-Šê
-LDßø`‘TDOêtTÝø ÁD…êˆêJDBDßøDOêrB„ê ØD‰ê CDßø0KDÝø$OêssÝø°ÈD‚ê ‰ê EDßøMDOêõUƒê ÐD‰ê DDßøü€LDÝø  OêtTàD…ê BDŒê „êbDßøÜÀOêrBÜDˆêcDßøÌÀCDÝø €Oêss‚ê Ýø(°ÄD‰ê eDßø°ÀMDÝøOêõUÌDƒê dD‰ê ßø”ÀLDOêtT¼D…êg@bDÒ OOêrB„êÝøÀWDˆêûOCD‚êOêss_Dˆê}OEDOêõUƒêgDˆê<ODDOêtT÷…êºf@’h›`FhërB†hB`¤Æh„`­Å` ž>¶ñÿ? –ô¸¬ °½èð
+ê
+”DJê
+
+˜‹ê \DOêtt
+WD˜†ê
+Šê
+WD
+Oê÷WVD…ê
+˜Šê
+MDVD„ê OêvV
+TD ˜‰ê ‡ê
+MDOêuE
+†ê TDOêtt‰ê OD
„øQ  „øR „øS0ci„øT0
-„øU  „øV "„øW0ÿ÷Yü
+„øU  „øV "„øW0ÿ÷
jp ªpëpch+q
jq ªqëq£h+r
jr ªrërãh+s
-js ªsësp½
-|ëô4?Gê '‘øÀ:CÏ|Bêg¹J—}²…êRD&@^@?’}ë²"Gê '>CÏ}Fêg°N—„êÝø°@o@‘øÀ^Dó~Û~ësc?Gê 'ÝøÀ>CÏ~Fêg¤N—‚êfD@g@uí‘øÀë5U?Gê '‘ø!À>CÏFêg™N —ŸÝø$€¾ƒê/@4W@‘ø `ä‘ø"pëô4?Gê '‘ø%À>C‘ø#pFêgŒN
-—…êFD'@_@²Ò‘ø&p‘ø$`ë²"Ýø(‘ø-€?Gê '‘ø)À>C‘ø'pFêg~N —„êND@o@óÛ‘ø*p‘ø(`ëscÝø, ?Gê ,‚ê@Lê‘ø+Àg@Fê lpNVDu‘ø,`í‘ø.pë5U?Gê'>C‘ø/pFêg¬õ$FO> —ƒê/@4W@‘ø1€ä‘ø2p‘ø0`ëô4Ýø0°‘ø5?‘ø9 Gê(…ê'@Hê‘ø3€_@FêhVN^D‘ø=°²‘ø6`Ò‘ø4pë²"6Fê &„ê ê 7C‘ø7`‰ê GêfJOGDû‘ø8pKD‘ø:ëscOê IIê
-)‚ê
-ê
-
-Iê‘ø;Šê
-Gê i>O÷}‘ø>pUD‘ø< ë5U?Gê 'ƒê ê Gê
-
-‘ø?p‹ê @1JêgßøÈ ÊDTDßøÄ \D…ê ëô4ºDê RD‹ê ßø¬ ZDÝø °ë²"ÚD‚ê ê SD‹ê ßø” [DÝø °ëócÚDƒê ê UD‹ê ßøx ]DÝø0°ëõUÚD…ê ê TD‹ê ßø` \DÝø°ë´DÚD„ê ê %àx¤j×V·ÇèÛp $îνÁ¯|õ*ƇGF0¨•Fýؘ€i¯÷D‹¾×\‰"k“q˜ýŽCy¦!´Ib%ö@³@ÀQZ^&ªÇ¶éRD‹ê ßø̤ZDÝø°ë22ÚD‚ê ê SD‹ê ßø°¤[DëócâDƒê UD ê ßø ¤‹ê ]DëõUºDTDßø¤…ê ê ‹ê \DÝø°ë´DÚD„ê ê RD‹ê ßøl¤ZDÝø,°ë22ÚD‚ê ê SD‹ê ßøP¤[DëócÊDƒê UD ê ßø@¤‹ê ]DÝø°ëõUÚD…ê ê TD‹ê ßø ¤\DÝø(°ë´DÚD„ê ê RD‹ê ßø¤ZDë22²D‚ê SD ê ßøô£‹ê [DÝø°ëócÚDƒê ê UD‹ê ßøØ£]DÝø$°ëõUÚD…ê ê TD‹ê \Dßø¼³ë´DÃD„ê
-Íø ZD
-ê Ýø ‹ê ZDªõ¸+ë22«ò¾k[DÝø°‚ê
-Ýø(°šD¶Kë:z[D‚ê ‹ê
- ]]D²KÝø0°
-ëuU[DŠê ‹ê ®K\Dë4D…ê
- KD‹ê šªKZDÝø °ër"[D„ê ‹ê šDÚD¤KÝø°ë:z[D‚ê ‹ê
- ]]DŸKÝø$°
-ëuU[DŠê ‹ê ›K\Dë4D…ê
- cD‹ê ›—J[D„ê ës#¬õ€²‹ê ’DÚD‘JÝø°ë:z¬öƒ<ZDƒê ‹ê
- U]D‹JÝø°
-ëuUZDŠê ‹ê \D†JÝø °ë4DZD…ê
- Ó‹ê š›DKë{+Ó„ê‚ê šD’D}J ë:z‹êBDƒê
-RŠê ÒxK
-ërRûU@vKdë4Dë‚ê
-e@›D«DqKë{+ëkêe@SD[Ýø$ lM ë³cUDcê
-Šê
-ªRDhMë²RÝø MDbê ‰ê ,LDcMÝøëtDMDdê ‰ê «DËD^Mëû+Ýø EDkêˆêëCDYM ë³cUDcêˆê ªBDdDë²RÝø ÀSMbê Ýø ˆêDDeDëtD«DÝø(€dê LMŒê ãDëû+EDëIMkê Œê cD} ë³cªEMcêÝø0À‡ê ÒMDë²R,@Mbê _@äuëtD«D<Mdê<OV@³DUDëû+ë9Mkêf@›eD ë³cªcê†ê ’ïë²R< Ÿbê ^@¤.NëtD¾dêU@^Dvh[`Eh‡heçÄhëö&‡`F`Â`Ýø4€ñÿ8¸ñÿ?Íø4€ôà«°½èðöq‡"am 8åýD꾤©ÏÞK`K»öp¼¿¾Æ~›(ú'¡ê…0ïÔˆ9ÐÔÙå™Ûæø|¢eV¬ÄD")ô—ÿ*C§#”«9 “üÃY[e’Ì Ñ]„…O~¨oàæ,þC£¡N‚~S÷»Ò×*5ò:½‘Ó†ë]/ÖSDæ¡ØÈûÓçæÍá!Ö7Ç ÕôíZEéã©ø£ïüÙogŠL*‹mpµF F?+ Ù8Kë"8H9I{DxDö¬yDGðþGð/þÊ€!vZ8*Ùñ
+js ªsësp½:
„øQ  „øR „øS0ci„øT0
-„øU  „øV "„øW0ÿ÷1û
+„øU  „øV "„øW0ë÷Çþ
jp ªpëpch+q
jq ªqëq£h+r
jr ªrërãh+s
-js ªsësp½
-EFHê'F›Ñ¡SF‘EàÓF£à
-ë çF»/F<àOð
-Ò+³BÙˆH}"ˆIˆKxDyD{Dìç,Ù¤ñ žBÙ´BbÒFê¹F;C³F™¢FÑc“Càë àBFÍø ÀPFYF›˜GÝø À
+js ªsësp½ª
ñ
-Êë *âØ(à›PFYFBF˜G
+«ë +âØ+ AF8FDDoðûU"ñ÷ù
+
+æç ñš›AF F˜Gz
+šYFHF›˜G ë
+F’ñ÷–øë
+
+ñ
+šA@Fñ÷”øºñéÑÈF ñ ñ ×ç,ÇØ;C››Ñc²F¡F“«“›£ë +‡ÙOð
+«(ðDRøXF‘ñ÷Xø™A@
+ë
ñ
-ÝøÀÊë +ÖØ%ð8FIF"äöðò÷×ú
-ßØ:àXF©BF›˜GÝøÀOð
- ñ ºñÄØ%ððäö‡ç› F©BF˜G
-œ
-ñ
-+]>S@+U4ðø;SF ±
-+C݄
-ë³F“»“@à¹(F)FBFÈG*]ø 0S@+U4ø 0ð ñ àOð
-+C˜Ñ
-ë³F“»“Aà¹(F)FBFÈGø 0*]Z@ø ñ +U4ðàOð
-ž”L
-àh'
-
-ð
-šø0¨©’"Cú
-óú
-úð ¿
-
-ø0#ðAJê
-ø ÿç\EÏÑ°½èð —
-1F$¿Ìñ
-
-ê
-g@Äé ‰FBðaAÝégOê6n@O@óÝé
-Äég “Ýé #Äé
-IOê0
-#@{Oê6Àñ
-#P@Y@Íé Ýé#ÄéÝé
-P@Y@ÍéÝé#ÄéÝéP@Y@ÍéÝé#ÄéÝé P@Y@Ýé
-
-Ýé #€ê
-
-ƒê Äé*Äé.#ÝéÝé#€ê
-ƒê Äé0Äé2#Ýé#Ýég‚êƒê Äé4#†êÝé#‡ê Äé<gÝég‚ê
-ƒê Äé6#Ýé#‚êƒê Äé8#Ýé#ƒê ‚ê
-Äé:#‹ê KŠê
-ŸÄé>«{Dž;`K{D3`!°½èð
-L2FÉ
-àl±, Ù@ò‘C
-à
-¹ ¹8àù±Âhõ€v F1F
-FàëøK‘ø@
-ë ñ@à
-ø
-ñ’ø@ð
-ΐ
-àOð
-ñ
-šOð
-˜,Ññ&F“
-ë OF“màE¹š@F™4›˜G"ºÈø ëø|ñ ðê
-ëåÑ’F¸ñ
-ø3A@‚ø?CEñïÑËøh
-ø ’ø@
-ø3KEñïÑÈøh‘
-HêSxÐøh1¹Ðøl!*±ñ@
-#b@k@Çé#n±¹ñ Ø@F1FJF/ð
-Fÿ÷›ÿ0Fñ@,4¿"F"½èp@ð÷ì¾-éðGä°F‰F’FFlŸÝø´DhC¹@òüC
-àjššB
-Ò@òÃC
-àn›¨!FRF
-‘
-¨ ’ ñ"“Rð°ü›P±@òlS
-à+±“!F;Fÿ÷:ýà!F;Fÿ÷ˆû€¹Ïçi}¹Ôø€"
-à1]4xñ=ðJ@ø+BF ¹©F*à
-àë
-"¨ð÷Ýü1"¨ð÷Øü™xšÉë
-ž|D
-õpè
-õ’q
-ñ
-ñ þ÷ÛýPF!F"ð÷1ü °½èð-éðGF­õ
-w³
-¨0!ÄøaMðÆù F
-©2F3Fÿ÷²þ¹Eð ûÄøaÔø1³õ€_Ó¨0!Mð²ù
-Øó#
-Kê› ë ’
-
-K1F h{DöÒ
-F
-ٌ#
-ÿ
-à
-ñ
-ÚEÑ@òw
-àHF™ñ÷Îù
-àPFIF:F#Fÿ÷ÉüF(»àHFIF;Fñ÷Éý
-Ñ)ðsù@òk
-ñ$ XFð÷1ü¸ñF¿C
-ÐÈ#
-Ûë#
-öòà
-ñ
-ªñ³ Fð÷™þ
-
-@òÿvà!Fšñ÷yû
-éç
+Íç
+t¸ç'¾ç-éðO…°™FFFF›0±)±¹ñ
+ñ
+
++îØOêoðûˆOê¸ñ
+ø 3˜EõÑDD·ç*F’ð÷—þ
+ë
+ñ
+ ñ
+ë
+œ~D– ž
+Ÿ ›±±±±c¹Kä"IH{DòysyDxDOðßùOðñùhC¹F F
+“"¿Éñ
+“›š
+«CømFhv±“F–Íé
+°p½øiæç
+F›!F–FÝø\€“›
+F›!F–F“›
+#[Oê2Íé#š›BêÃu› šð[BðaCS@šÄé#šÄé%š™˜‚ê š™Z@ ’Äé š‚êš‚ê
+p FF˜F1ð-ÿFÀ±
+
+r&àáø ‘ø@ 3ðñÿ7‚ê
+QE¿HEÀðÙ€Ôøh1Äéš“Ôøt1C±ñ`ñ@
+ñ@ ñ
+ñ
+3
++ÇØOê6Oê ˜DDoðû Uͱšñ F›˜GNDñ@
+QE¿HEÀð×€Ôøh1Äéš“Ôøt1C±ñ`ñ@
+ñ@ ñ
+ñ
+3
++ÈØOê6Oê ˜DDoðû Uűñ›š F˜GNDñ@
+ã`ñ`›ñ@™DíVE:Ñå±Ôøh1ZFñ F˜Gññ@
+“úƒøÐOêë Fñ`“ñ@“·BHÑ›IF
+
+¸G˜úˆóã`ݱÔøh1ñš Fñ˜G˜úˆóñ@ã`
+Ôøp!FêSvOêÀ Û
+Äé#8Fð÷ŸûÔé#ÔéB@K@Äé#Ôé
+Ôé#B@K@Äé#m±¸ñ
+ØBF)F8F1ðTú°ú€ð@ °½èð
+úr›[¹Öø2ƒ¹n›1Fmš(F
+ñ"
+¨ï÷sú ™‘úû
+™‘úü¼ñÿ?Íé
+¼¿»ñÿ?ÐÔ鈌E¿ƒEÒ@òdC}"
+¨ï÷ú
+›º ›º”ø02Íé
+#±
+¼¿»ñÿ?ÐÔ鈌E¿ƒEÒOô™c}"
+ë"˜“ï÷ƒùë"˜ï÷}ù™ ë
+ñ
+
+*ÍØ: D‰Doðûw
+œ~D–
+„¹ õ}½èðKB"IH{DòÙsyDxDMðýMð#ý´õ
+º˜™
+•³ RF
+§çÔø1ë5"FHFº3ºÄø1Ôøô0˜GªEîØéç0/„Ø:FYFð÷ãÿ
+®0!0FUð­û
+M}Dòdv0F6ðøÕøh70FÅøhGÄø16ð øëç
+
+
+
+F©ï÷oÿ¸±˜oð@H
+š‰
+‚
+þFH¹
+F
+ÑÔø|"9FÔøxî÷Oü Äø„ºç-·ÝÔø|2[+²Ý*F9FÔøxî÷>ü3i
+¹™B÷Ñ Äøü
+ñÿ2{D3ø€#‹@;oê“7K{D“7K{D“#9FF Fÿ÷Jÿ(¹
+Ü Fñ÷…ø /¿›ÀC€E(¿€Fßøˆ°
+8Fð÷ ÿF
+ ñÿ;»ñ
ñ
-²EåÝ&(Fð÷êÿ
-)-é÷CF‘FFØO#
-à¡ñ B
-ÙT#
-Kq"{DËçY2Fî÷Oý >`þ½ºb
-)-é÷OF‘FFب#
-à¡ñ žB
-Ù­#
-öú
- àXF!RFþ÷Vúàñ «x
-.
-ØË#
-„ð
-f@ ê C+êat@#êäv>¹í#
-K‰"{D¹çHFy*Fî÷…ü› `°½èð
-´ëJÀð›€îC60F,ð3ýF@¹OôÎs
-ê'ê
-)ê 'ê
+ÓEÑ@òwn"
+
+ÛOô‹sk"
+¿Oð
+à8Fð÷«ý0±@ò_l"
+ñ$F“ð÷¦û.
+K{DÐç
+Ù@ò7l"
+@1FDø# :F›ó÷CþCÉø
+PFó÷Œù Fð÷æý ˜ð÷éüÀç
+ Fð÷+ý
+š™ô÷0ù
+šƒê
+FF¨ÿ÷|þ±˜°½Oðÿ0úç-éðOF‹°FFFšFî÷)ü)ÜOôös
+)-é÷CF‘FF ØO#~"
+Øf#t"
+)-éóGFFF ب#~"
+ö6
+Cpö6ñ Fþ÷2ú¡EѨ
+.ØË#~"
+
+ Ch@!êàt,¹í#
+àš’âREÒ@òMr"
+)FZ“›ë
+ÑOð ççø5ø/J@päçø/é\3J@:pëç
+
+
±h` ±Âh`½ ±i `
±Ci`pGµ ±„i `
-±Ái` ±j`½øµF@h FFF
-X˜BÐ6Càšø0œB Ð@òÍ
-ñ2Fî÷zù¨ ™"Fî÷uù =`Èø
-FðB±Oô!s
-±¢hZ¹@ò‰#
-!à<I¨"yDöÿö÷gý
-¿Oð
-¨ö÷*üºñ
-±‚h:¹w#
-Ò‚#
-àÊø
-±‚hB¹@ò±
-s
-ÐOô s
-ž?j œ'±
-– • ”°½èð@ÿ÷_¿°ð½ðµF‡°FFFFþ÷»ÿ ™F
-žÿi œ'±
-– • ”°½èð@ÿ÷‰¿°ð½-éÿGFF‰FF ›lh£B Ð@ò#
-¨Nð&ý Fþ÷þ*ð¥ÿFP¹@ò73
-© "+Fÿ÷ ÿFX¹OôOs
-© "è
-ºñÿ‡°F“F™F Ü@òŽ3
-H!F2FxD
-I{DxDõ/cyDAð/üAðAüñ\
+±Ái` ±j`½øµF@hFFF
+
+K{DÁç ›`
+ ñ@PF¯î÷Yÿ@F ñh î÷Tÿ8Fî÷QÿHFî÷Nÿ«F“î÷Iÿ$«F“î÷Dÿ)¨î÷Aÿ3Fbi!iPFò÷^û»Oô1s"
+¨Íø
+›3¹@òë#o"
+j
+FPF›F‘’Ýøö÷nÿ›»ñ
+ªñ£BÒOôs
+ñÿ3 ñ
+“PFó“ö÷Íý
+ÐOôs}"
+“FFCh ‘ ±Ãhƒ¹@ò‘#"
+™(Fî÷¿û
+Ñ¥K@ò12¤I¥H{DöˆyDxDJçãhS¹¡K@ò32¡I¡H{DöˆyDxD=ç0Fî÷€ý0Fî÷·ýF0Fî÷³ý¹ñ
+ñ“›3“ ›ñî÷>û
+ÛrK@ò]2qIrH{DöˆyDxDÒæ
+™ ˜î÷OúFȹ@òý#F
+šþ÷4ú
+šþ÷rûìç
+¯ "
+K ,F{D(ðüþâç
+
+
+H!F:FxD
+
+“õc“(ðÔûÿ÷ØÿFð±›ÿ+Ü@ò9C~"
+›OôŽb¼I½Hõ'cyDxDIðÚüIðìü¸õÀoÚ š9F8Fñ÷ú
+H{Dõ)cyDxDIð×úIðéúñ\
ci„øV „ø[0„øX  „øY 
-„øZ "ã÷ý
+„øZ "å÷þ
ªpchëq*q jq
ªq£hër*r jr
ªrãhës*s js
ªs#iët*t jt
-ªtp½öx
-K„è
+ªtp½Â²
#j„øb „øg0„ød  „øe 
-„øf "ä÷ý¦f8F1F@"ì÷,øãn+Ð +Ñà£Y ªUª6Qp.Oê!Óp‘pòÑ ø½£Y ªUª6Qp .Oê!Óp‘pòÑïçØ
-àTø&06ëp*p jp
-ªp5ãn¶ë“ðÓÝç0Fø½
-#£Óé
-#£Óé
-ë!F€"0F€4ë÷HþHF1F"æ÷™ø++ñبñ€ð#ð€3šD
-àQFOêØÂDðHFÈë
-
-æ÷‚ø¸ñ
+„øf "æ÷°ü¥f@")F8Fë÷Kúãn+Ð ++Ð?Ø0Fãn0µë“"ÒTø%05
+
+øƒBïÑ ø½3<ñ$
+øƒBïÑèç(FççÖ®
+#£Óé
+#£Óé
+Së $¿&
+Ù
„øË0„øÎ „øÍ„øÌ 
-„øÊ  „øÉ ¢l„øÈ0ãl„øÇ 
+„øÊ  „øÉ „øÈ0Ôé#„øÇ 
„øÃ0„øÆ „øÅ1F„øÄ 
-„ø  „øÁ "„øÀ0å÷çÿ½³ÔøÔ00+Ð@+1Ñà<ñ0Tø?bhëqêp(p hp
-¨p*q jq
-ªq5BëÑ p½<ñ@Tø?bhëqêp(p hp
-¨p*q jq
-ªq5BëÑåç
-Ø@ò%
-¯˜í÷Ùû¨D!)ðzý,¨D!)ðvý=¨D!)ðrýN¨D!)ðný_¨D!)ðjýp¨D!)ðfýà F
-°½èð‡
-°½èð‡
-°½èð‡
-°½èð‡
-HLxDð2ü¨ð^ûhFðµû F°0½
-‘©JDð¶üF@¹(FIFFðtýÄø
-¨ðÞüÚø
-ªùDÙø
-¨ð•þ°õ
-¨Šð¥ÿ
-¨ð,ý¨ðý F°½èð‡
-“ «“è
-•sa3šB4aµhÓ
-©"(FKðBú¨Eð]üF±(šKð9úK
-H
-3yD>ð…ú>ð—ú Fp½
-Mÿ÷óý
-K}D FëX3@ø;ÿ÷¢ýñ<
-Mÿ÷3ý
-K}D FëX3@ø;ÿ÷âüñ<
-Mÿ÷qû
-K}D FëX3@ø;ÿ÷¦ÿñ$
-þK}D FëX3#`8½
-JµF{D›X3@ø,;ÿ÷aÿñ
-ñÒ@FDðÙû‚EìØà!F(FDð üAFF8FDðü
-K FYøEðhøF(FDðÞû(FDðìû
-ñÒ@FDðû‚EìØà!F(FDðüAFF8FDðü
-K FYøEðøF(FDð×û(FDðåû
-ñÒ@FDðEû‚EìØà!F(FDðûûAFF8FDðúû
-K FYøDðÔÿF(FDðÐû(FDðÞû
-‡
-ñÒ@FDðûú‚EìØà!F(FDðôûAFF8FDðóû
-K FYøDðŠÿF(FDðÉû(FDð×û
-ñÒ@FDð±ú‚EìØà!F(FDðíûAFF8FDðœù
-K FYøDð@ÿF(FDðÂû(FDðÐû
-JµF{D›X3@ø4;ðùñ
-JµF{D›X3@ø ;ðuùñ
-JµF{D›X3@ø$;ðAùñ
-JµF{D›X3@ø$;ð)ùñ
-K JµF{D›X3`@k±Dð{þñ
-K JµF{D›X3`@k±DðCþñ
-K JµF{D›X3`Àh±Dð)þñ
-
-àH
-ñ“è
-ñ“è
-ñ
-ÊEô7¯Oð
-•HF –AF:F#F°½èðCÿ÷u¿°½èðƒ-éðGš°F®¨ˆF‘FšF¬CðÅþ0Fý÷Ÿÿ Fý÷œÿ+h(F
-FFððûK}D FëXæ`3#`p½’v
-MFFý÷wþ K}D F
-Ü(5ÐÜ(/Ñà(Ð(*Ñà@ò˜BÐÜ@ò˜B Ñà°õ‚Ð@ò˜BÑàHxDpGHxDpG HxDpG HxDpG HxDpG HxDpG HxDpG HxDpG
-HxDpG
-HxDpGý7
-I
-Û)F˜
-Hà›+Ø F0! "Hð>ýà(F!F "ÿ÷ÿ
-à˜"hÿ÷Eþ
-àoð(à `CðŽûF0`
-K{D `ÿ÷ãÿ `
-i
-HxDðù¹àoðc
-K˜B ÐX¹˜<ðÐù
-H
-L Kµ"|D‹!{D F
-e
-þб(Bðôýh™[i˜GF¨¹à®)F0F 4Bð•ý–è
-­(F“³k “Bðnû;h©6k ¨Óø BðhýñAF“ñ<“2F «
-KF¦hâh{D3“è
-KF¦hâh{D3“è
-®­0F7ü÷þú(Fñ
-ü÷ùú¨Bðú8FBðxühFñ4¨Óø(°Bðü©RF«
-ü›à`#a¨Að'þ8FBðÆü¨Bðëù(Fðµý0Fð²ý°½èð-éðOF“°FF
-BðñûhÛk˜G„F@FÍøÀBð¦ûƒF@FBð§ûF FPFAFBð¶ûñ8ÝøÀ“YFÖé#`FÍø
-BðƒûhÛk˜G„F@FÍøÀBð8ûƒF@FBð9ûF FPFAFBðHûñ$Íø
-ªBðû
-ñ8FBð×úhÛk˜G
-ñ
-Ó+h x"sZxbsšx3¢s+`ø½
-ø Fü÷Hø F8½ˆE
-)OFFD"ØÃh;¹àPø5
-K&aö
-KµF{Dõs`€h±Aðsþñ
-KµF{Dõ s`€h±AðSþñ
-ÒHu"IKxDyD{D9ðbü9ðtü½ço
-I{DxD3yD9ð:ü9ðLü½˜o
-Ó"F@F1FFðöù+h ,`½èð
-ü"i ãh§`Ó#a
-i`Ka‹aËa bKbpGKÁhiH{DXhh"Eð·¾G
-M
-,h…KœBPÜ;œB€òž€‚KœB
-;œB€ò’€;œB
-аñ€O<Ñà°ñÀO
-аñàO5Ñ à0F9Fñ?ð®ü4à0F9Fñ?ðYû-à2hx+"غB Òð +r3h33`à0F9Fñ ?ð’üˆ±0F9Fª?ðŒüh¹
-à™ÈëŠBÜ‹BÜBD ª`à
-H)FxDþ÷‘ø F!ÿ÷Àúà%¨@ðßù a¨?ðþû(F|½
-à H
-Ÿ ž¹;àDh
-ØFOð
-¨1F:Fþ÷sþ
-ݣB
-FÑ<H!FxDý÷ÙüPFLà¸ñÿ?Ñ Gàø
-Oðÿ6+Mßø¸à
-¨!FRFþ÷Åý
-›«BFÐKEDÐ%J“B¿VF
+„øÂ  „øÁ "„øÀ0ç÷hø-±ÔøÔ00+Ð@+#Ð
+ø ø  ø 
+ø
+BãÑ p½ñ<H5Tø/3ahø ,ø ø  ø 
+ø ø  ø 
+ø
+«BãÑÜçµ FAhFÿ÷\ÿ`¹Kç"IH{Dön3yDxDHðäüHðöü½
+“ô÷þFì÷·ÿ±0¹Oô´sA"
+›)F`hZhì÷…û
+F1Fÿ÷ìü!F(Fÿ÷—ý FØ!+ðâü(F6°p½ÿ÷Ž½pµ¶°lFF FFÿ÷èû F
+F1Fÿ÷eý!F(Fÿ÷íÿ FØ!+ðÈü(F6°p½-é÷O‚Fœh‹FFFd¹U#e"
+“› “
+›0FÍø
+›Íøh”“ ›“+F °½èðO÷÷‰¼ °½èð
+ªFBø=)FðáûFh¹Oô…sF
+°½èð¬J!F(Fðû`±(Fð~ù@¹ßøT€­ Fðwù€¹$
+à@òd"
+¬Oð B!F8Fð¯ú
+ÿF˜+ðú˜+ðŠú F°½èðƒ "0F¹ðÓøб® F"1FðúFP¹Oô sF
+Oð BQF8FðWù
+"ñ((Fðõÿ
+ñ2
+HFðzÿ°¹š™
+°p½1F F'ð
+©(FAø=ÿ÷ÿF(±˜›šDšBÐ Fÿ÷ˆÿ›#h"
+­€!(FÍø€ð„ùx¹(Fð³ù
+©8Fðàþ
+#
+à8FðæüF
+K{Dæçbh±!hSðÜøbhäç±!hSðÖø+hbhD+`ôç
+•JQF@FðFø
+"QF@Fð-ø
+Oð BQF@Fðø
+"QF8FðÁÿ
+Oð BQF8Fð­ÿ
+;JQF8Fð’ÿ
+“«Íé
+Íø
+ëðeþ
+ñ8Fð+þ
+ò÷lÿFHFðyýFHF õÈyð‘ýÍø 3FÍé
+Fðhþ
+ª ©T¨ð·üFïå
+«øMêhxD©h
+ ñp xD
+!`oðxD
+‡$*XÑßø¼
+AF ñpxD
+!`oðxD
+FoðxD
+AF ñà
+ ñ Oð
+xD
+ñ“
+xD
+ ñ xD 0 ðóý!PFðtýßø7IFzh¨ëX’BD3“ßø
+ ñ xD
+D ð€þ·äßøÔAFOð ñà ñp
+xD
+D ðþëçßø
+ ñ” ñ xD
+D ðzýáçßøAFOð ñà ñ
+xD
+D ðþüççÊHAF ñà
+ ñp Oð
+D ðüíç˜HAF ñà ñ
+Oð
+D ðDûçßø8 ñpxD
+ðÜû;h@FH+¿+hšaßøì;{Dh“ ðû `Mð¨üF0FMðþù1h
+D ð½úÿ÷Z¸"h@F
+D ðµúÿ÷§¹ßø@ AF ñp ñ
+xD
+ÿ
+ð{û;hHFH+¿+hšaßøÜ:{Dh“ ðgú `Mð üF0FMðcù1hq¹ßøÀ
+!`oðxD
+D ðSúóçßø˜
+AF ñp ñ
+xD
+ðdû;hH+Ñßø@:š{Dhaßø8:HF{Dh“ ðú `Mð©ûF0FMðÿø1hq¹ßø
+!`oðxD
+D ðïùóçßøð AF ñp ñ
+xD
+ðJû;hHFH+¿+hšaßø9{Dh“ ð¢ù `MðHûF0FMðžø1hq¹ßøt !`oðxD
+D ðŽùóçßøL AF ñp xD
+ð5û;hHFH+¿+hšaßøì8{Dh“ ðCù `MðéúF0FMð?ø1hq¹ßøÐ!`oðxD
+D ð/ùóçßø¨AF ñp xD
+ðñú;hHFH+¿+hšaßøL8{Dh“ ðäø `MðŠúF0FLðàÿ1hq¹ßø0!`oðxD
+D ðÐøóçßøAF ñà ñp
+xD
+ðÓû:hH*Ñ+hšaßøˆ7PF{Dh“ ðsø `MðúF0FLðoÿ1hѹßøh!`oðxD
+D ðSøççoðPF ðˆüþ÷ê½"hHF
+D ðEøþ÷µ¿ßø AF ñà
+ ñ Oð
+ð²ý;hH+Ñ+hšaßø”6HF{Dh“
+ðìÿ `Mð’ùF0FLðèþ1h¡¹ßøx!`oðxD
+D
+ðÒÿíçßøDAFßø@†­xDøD
+ðÐù;h(FH+¿Øø
+ð§ÿ `MðMùF0FLð£þ1h9¹!`oð(F
+D
+ðšÿóçßøàAF ñp ñ
+xD
+ð»ù;hH+Ñßø5š{Dhaßøˆ5HF{Dh“
+ðPÿ `MðöøF0FLðLþ1h‘¹!`oðßød5¨ëX3“LðÑÿàoðPF
+D
+ð8ÿèçßø<AFOð
+Oð
+ðmù;hH+ÑØø
+ðÜþ `Mð‚øF0FLðØý1hi¹!`oð(F
+D
+ðÉþíçßøtAFOð
+ ñp xD
+»’
+ðý;hH+ÑýKš{DhaûKHF{Dh“
+ðgþ `Mð øF0FLðcý1h™¹ôH!`oðxD
+D
+ðNþíçoð˜
+ñ“
+D
+ð:þíçÞHAF ñpxD
+ðdü;h@FH+¿+hšaÏK{Dh“
+ðþ `Lð¨ÿF0FLðþü1h
+xD
+ðªý `LðPÿF0FLð¦ü1h¹¤H!`oðxD
+D
+ð”ýóçoðHF
+D
+ð†ýóç’HAFOð ñà ñ
+xDõ8 ð0üK¨Íøt°ëX3Iøp=
+ð=ý `LðãþF0FLð9ü1h¹tH!`oðxD
+D
+ð'ýóçâž
+ ñp xD 8 ðÿú!PF
+ðü `LðªýF0FLð
+D
+ðëûíçŽHAF ñp xDO8 ð™ú‹KªyhHFëX‘AD3“ˆK{Dh“LðÀú
+ð«û `LðQýF0FLð§ú1hq¹uH!`oðxD
+D
+ð—ûþ÷4¹oðPF
+D
+ðˆûóçdHAF ñpxDb0 ð6úaK!@FëX3“_K{Dh“
+ðQû `Lð÷üF0FLðMú1hQ¹OH!`oðxD
+D
+ðAûþ÷Þ¸GHAF ñpxD»0 ðîùDK!@FëX3“BK{Dh“
+D
+ðíúóçoðPF
+D
+ðßúóçô¡
+J IzDRXñFBøÂ`
+K JµF{D›X3`Àh±Lð¯ûñ<
+JzDòBÙç JzDõzrÔçJzDõ~rÏç
+K JµF{D›X3@ø8; ðÿÿñ$
+JµF{D0šX2@ø,J›X3@ø<Lðæø F½
+K JµF{D›X3@ø<; ðÿþñ
+IiŠBØ•
+IiŠBØ•
+IiŠBØ•
+IiŠBØ•
+IiŠBØ•
+ý£ip`³` "AFñ
+Ѳh
+¹©ia±ÖøÀii¼ñ
+ðü±Íø$€H! ”xD,0
+ðü
+±# “ ñ(­›RFAF
+“# “›ÿ÷åþFPFKðÕü F °½èpoð%õç
+°p½
+ðšûUK(FUOñ óX%wD3#aRKóX¥b3#bQKóXF“Kðúû ")F`bñ,
+D“BÏÑñ“è
+«Íø(è
+“«Cø­“è
+«è
+“› “
+«“è
+šHF— 3Íø°“B–˜¿ “
+ðBþ F°½èðoð(ìç
+•BF9F0F°½èðCÿ÷f¿°½èðƒ ñ
+ðµÿCFÐF˜,0
+ðáÿƒhS±˜!F,0
+ðÚÿÕø˜0ƒ`#ø 0š ñ #FÕø˜H2ÿ÷ü@¹oð%0FJðÆÿ F°½èðš#FÕøœ H2ÿ÷òû
+þ÷ìû¯0FÍé
+ª ñ0 þ÷Ôû8Fþ÷Ñû›Íé ª
+XFJðóþ8Fþ÷Kÿ0Fþ÷Hÿ
+¨Jðêþ(F
+ðpý F
+ðmýPF9°½èð8F ðüþ(âÑ«@FFÍ骓
+«—“JF“)F– FÍø
+ð$ý¨Jð˜þ çoð%
+õçoð
+šç
+ð ü F½o1gðÑHxD
+ð’üðç
+ðiü•ø  ÍéFºñ
+ðWü1F(FGð
+øÍø °"–#•IFÍø
+ð4üOð
+ðüÍø °"–#•IFÍø
+ðüoð¸çFöw
+ðÜû«2F)F˜Dð—ú¹› +¨Ð
+H !šLxD
+ðóûŸç
+ð?ûoð0+`&`f`éçèF+FF:F@FðŽø+h
+ð û)F8Fðtú)hFQ± öä
+ðòú
+Ð-Ðoð;`
+ðÆúoð0;`Æø
+ð”ú9F(FðúF@h
+ðàÿ8³™!ð+/Ñ ñ ¨BFÿ÷iÿœ¬¹­BF™(Fÿ÷ïþœT¹7Íø 
+ð±ÿ
+ðÃùŸ›–
+ð¹ù#h ¯>`YFš FÓø  ;FÐGÈø
+ðÑùØø
+ðàÿh¹|I"0F
+ðÚÿF0¹ö¥@oð
+ð±ùàç"uI8F
+ðÌÿx¹sI"0F
+ðÆÿF@¹qHoð
+ xD
+ð›ùÊçkI"˜
+ð¶ÿF@¹jHoð
+ xD
+ð‹ùºçgK
+ðVù
+Ømh[i˜GƒF
+ðÉøœ›ØøZh‘B@ðK‚[FØø šB-ÙœšØø
+¨Jð2ûL¨
+ðù¨Jð|ú˜Jðyú¨Jð†ú¨Jðƒú¨Jðpúõæ
+ð†ø("
+ðûœJ«–!–’Oô€r ’ ª’è
+ðþú1F(F
+ðÑú)FV¨
+ð“øÝø|‘¹ñ
+ðø@FJðõù3¨þ÷Mú˜þ÷JúXç("IF(FNðrù(Fý÷»þ(F
+ð}ú)F8F
+ð?øÝø¤¡ºñ
+ð2ø¬çMK{DëJ
+ºù$·ôç#h ! Fi˜GF
+ð øÖø
+
+ð¥ù)FHF
+ðýÿ`h@"!iëhDñ
+ð½ø°½
+iËhhh ðÿ F½
+“›0FSø50F“
+ðû€F
+™F˜ðœúF9F0F¹ñ
+H*F™xD
+M K}DëX3@ø<;IðÄþKñ
+Iµ†°Íé#F«
+JµF{D›X‚h3`±
+HxD½
+ñÃø(@öû
+ò™õ`Áø ˜JFAFDMð<û#š1F(F
+F“K™{D[k
+Ñ1(FMðyù¨Ið ûíçoð%øç
+Ñ01(FMðÒø¨Iðbúìçoð%øçLöç
+KBF0FëXÍø
+F!h
+HxD
+•{D“Oðÿ3“«“ð:ûFp¹H!Foð(xD
+“› “ð«ù
+’õ€R2 ’ “õÀS3Oð “õÀS3“ßøè
+’õ€R2 ’«çOð
+Ðoð
+}D°ñ€_4¿À
+à@òº!(F
+K7µ F
+JF{D F›XF“Hð½ý
+XFšX2’/J›X2F”Íé D3Íé$D“Íé"CÍé&DLðûû2F!FPF–Lðõû«©“RFÍø
+Hø­)FBF0Fÿ÷®ø@±"HQFxD
+±K“`pGüÿÿ
+±K“`pGüÿÿ
+±K“`pGüÿÿ
+±K“`pGüÿÿpµFˆ°:± þ÷{þF ¹oð0£`°p½mF "
+š)F0FLðúh¹ FSFJF)Fÿ÷™üF@FHðrúÛçoð0øçoðcõçj{
+`pGHxDpG(úÐ(ÑHxD0pGFpGd‚
+`pGHxD0pG(ùÐ(ÑHxD0pGFpG
+à/I" FyDLð3ù
+ù¸±I" FyDLðù±I" FyDLðüøh±I"yD·ç Æç Äç Âç Àç ¾ç ¼ç
+šBÌØ"F)D0FKðîÿ FÇç(ØÐÂç
+K@ò×1
+H•{D”“xDK&0‘{D
+H{D
+K LµŒ!{D|D
+FF{Dhðbº
+³õ€?7Ò£õ€v6 ð³@£õ€T$ ð£@4C£õ€G? ð»@<DÄëÓ4ñ4"úóðëDGhOð úü
+D“B€ðí€ÒéðCð#Ck`BðK`¹aú`Ðçxi†B'ѹh
+D“B
+
+ñ(
+PEЄEØÂh–BÐ?ð…üˆBÑ
+Úø0!–B:ÑÊø0y³ŒE»Ø0iÁø€±„EµØaapi
+)Ôø
+C™ðË@
+DYðË@
+DÃó@Ë@
+DDL3Tø#0ZhF"ðRi
+Åñ
+
+±õ€?:Ò¡õ€w? ð¹@¡õ€V6 ð±@>C¡õ€NOêNðúñvDÆëÑ6ñ6"úñðëFÔøàOðúø
+-Š¿ 5%%ðàçØø
+.Š¿ 6&&ð
+ûû) FYDÿ÷<ü
+ñÿ:’E ñGø"0ÐƹXø"0
++Ù 3#ðCðäÉø2™DéçQø+
+*Š¿ 2""ð“D›ç3Fëç#éçDðÉø@8F°½èðFùçr
+²õ€?=Ò¢õ€t$ ð¢@¢õ€Q ðŠ@!C¢õ€G? ðº@9DÁëÒ1ñ1&úòðëAGhOð úü
+*¡ñŠ¿ 2""ðþ÷Áÿ±
+*¡ñŠ¿ 2""ð)Fþ÷ˆÿ…BèÐæç)øµFØF½èø@ÿ÷P¹) F8¿#YB ÑFoð?›“B Ø?¹
+*ñ Š¿ 2%"ð8F)Dÿ÷)ù
+DÄé
+ÑêhëišBÙ
+ÐK{DšhSRBD@Àø¸FpG
+°½èð‡ÜøpGD»BÛÒ™EÙÐ_h/ÖÐ'ð
+ð/PD¿QDñSDÈçJFIFKFMFOFÎFHFÍçÌh
+)4¿%oð  D2¢û#©ë“ OôÈsû-˜¿7´õ™ Ó¤õ™t§òlw
+f
+Fy‡°AyCê!ð0fÐÅz +„zDê${DêDE{DêdÑY°ú€ð@ à0+øÐ+Ñ$±]€ð
+ø0ø  ø " ëø0ÿ÷ ÿ°]øûFÿ÷迵Ñé
+ø0ø øiFø 
+ø  ø "ø0ÿ÷éþ°]øûFÿ÷Ý¿FAêÂ[ÿ÷ÿ¾´ yð +Øßèð "$Jx xCê#ŠxCêCÊx!F]øKCêbÿ÷Ý¿$îçi ¹K{Da
+yBê"ðÀ@+
+³FOð
+|CêCJ|!F]øKCêbÿ÷ß¿´Ì{‹{Cê# |CêCL| yðÀCêc€)¿Oðÿ3F"±
+~CêCJ~Cêc ÑFF
+`§Õá絆°lF
+FF FEð¼ü0± Fÿ÷‹ÿ FEðáü÷ç°½µFF¹¹Kh{DšBÐnF-Ø*F1F Fÿ÷ïÿ°p½"1F Fÿ÷èÿ
+K{Dã`
+úó*úñ
+úòCêFêEêÑÈé
+`ÑÙ{š{0iBê"|[|BêB!FBêbHðÿrh1iÐ}“}Cê
+|CêCJ|Cêc2i
+}CêCJ}Cêc˜BÙÓ›;±ëh ¹UK{Dë`ÏçFõçIF(Fÿ÷Bÿ
+ÍéD”Eðù ñ“«h»¹
+xZ±Tø\4ÿ÷¥ÿF
+(¿3ßçK
+%#x
++’Koêðˆ¿&{D
+*ø\Ñ FHðOûaF FHðû#xø/ +îЮçÈFDFÀçFOð
+CIF"p;šÑÈD«àFÝç@úòð?bðø+ïç¸ñ&¨Ñ
+" Dð™ü
+0yDDðAûBI
+0" DyDHðÅù¹#¥øL0½èøÕøHÙø
ñ
- F?ðfý‚EêÓñ F¿Oð Oð
-KEh{D3`-±(F@ðø(F?ðû¥h-±(F@ð›ø(F?ð•û F8½ü
-Ó1F¨?ð7ÿ¨©ÿ÷ÿ›“à0F?ð>ÿ¨9F?ð~ÿ0F©?ðÿF
-# ŸÍø4°Íø0°žLŸNà¨9FBFþ÷ û›£B
-гBÐ ™™J“B¿AF ‘àÃFàÍø0€ñ8F?ð:û€EãÓHF9Fÿ÷3üF
-#AFÿ÷Ñý
-#ÿ÷:þ»oð7·à»ñÿ?Ñ ›3ÐVé#(F ™Íé
-#è0Fÿ÷3þF0¹'HoðxDý÷ùNàš
-#ÿ÷‚þFØ»HoðxDý÷÷ø4àoð 1àoð6.à¸ñÿ?¾ÑÛç
-JµF{D ™X?ðùF``?ð^ý`hF½è@?ðV½
-JµF{D ™X?ðàøF``?ð¨ý`hF½è@?ð¤½
-Ñ0F>ðZýHAFoð xDü÷+þà
-ÐHÀ"IKxDyD{D7ðÆø7ðØø F?ðýû ଠF?ððû F?ðÿû
-U
-ý àhh"F1Fhè€j«¨GFàoð(¨>ð=ü àoð
-àoðà+h(F1F[j˜GF
-KF{D83Eø0;(F=ðdÿ
-ÿ
-ÿ
-¨@ðñúFXFBð þ
-™RF(Fl˜GF ¨@ð‘ú ¨@ðú
-ú¨@ð úF
-¨@ðÈúàßø\¡¨@ð~úàßøP¡ ¨@ðVú ¨@ð¨ú
-¨@ð¥ú ¨@ð‘ú¨@ð}ú¨@ðiú¨@ðDúŠàoð
-‡à›+ôƒ®„æ ðîú‚Fèç.ðÂùF ¨@ðÜù ¨@ðÛù
-¨@ðÓù ñX
-¨@ðÐùƒF
-KáX=ðÙÿFH±©Aø 8F.ðDý…èP
-à ðèùF¨@ðù(F=ð@úà¨@ð¶øF¨@ð¦ø9FF"F F*ðÇøF0F@ðªø0F@ðø
-š GF
-L
-N M|D K~D}D0FáX*Fú÷ÙþK0*FáX½èp@ú÷Ѿ
-š8F;h1F
-Ø_+Ùš“BÓÛ#`àoð4
-#`àPFOð
-Ð+@ðŠ€ç÷ÀÿFBàè÷ øF>àè÷HøF:àÐøà0+Ð + Ð+uÑç÷‹ÿF.àç÷ØÿF*àè÷øF&àÐøà0+Ð + Ð+aÑç÷ˆÿFàç÷ÔÿFàè÷øFàÐøà0+Ð + Ð+MÑç÷¤ÿFàç÷àÿFàè÷,øFñÄ
-žˆFF Ÿ>³7³Fû÷äü«k8`¯ + Ñ(FAF"F;Fÿ÷[ÿ
-›ÿ÷„ú¹˜à Fû÷˜ü ›`
-FF
-žŽFF
-0F+`½èøƒ
-
-L
-N M|D K~D}D0FáX*Fù÷+üK0*FáX½èp@ù÷#¼
-@òÉ ê÷3¸@òŸê÷/¸@òË ê÷+¸Oô3pê÷'¸
-¨<ð5ø¨>ð û
-©ðŠûFP¹Øø
-ǬGF
-¨<ðMø ¨>ðSþàoð(¨>ðeû¨>ðœý ¨û÷ ü#àoð à˜ÿ÷þF ¨>ðþ ¨>ðþF
-MFFÿ÷éú K}DñT
-ù
-L
-N M|D K~D}D0FáX*Fù÷3øK0*FáX½èp@ù÷+¸
-‰
-D¤±FOð
-àoð
-àç÷¬þFàç÷¸þFàç÷ÄþF¹oð ãfà»ñ Ñ(Fç÷fü†BØ. Ùàoð8ãfà
-ýoð #`<Fzà«Oðÿ2Cø -HFFOð
-Kñ
-¨;ðLú¨=ð#ý
-©ð¡ýFP¹Úø
-ǬGF
-¨;ðdú¨=ð‚ý¨>ð[ù¨>ðûùàoðàHoð(™xDù÷ ûêç F™ß÷èÿ
-MFFþ÷iû K}Dñ@
-Oðÿ0 `p½ mæ÷ëþF kð}þs°ëCÒ mæ÷àþF kðrþFH1FxDù÷#øoð Oðÿ0+`p½ p½ p½n&
-Ò"F¨)Fÿ÷ØýFȹ¨9ð’þF0F:ðûF¨=ðßú"F
-L0F:ð9ú
-úF(Fù÷ù!F€F¨9ð™ýók+ Ñ™ˆE
-Ò¨*Fÿ÷Òü »¨9ðýÝø€F¨=ðàùF8F:ðúÍø
-Ò¨*Fÿ÷.ü »¨9ðéüÝø€F¨=ð<ùF8F:ð`ùÍø
-ÐÜ°ñ€_Ñà°ñ@_аñ€OÑ h½HÇ"IKxDyD{D2ðÔû2ðæû}þ
-
-Ü:“B€òg‚oô|bD“B@ð•á
-ÜoôÈ~rD“B
-
-#Þ÷éù ¹ ðøF#à¨<ðÊû
-™ š<ðþ ¹
- œÿ÷ úF¨<ðú¨<ðú ¹
-ª<ðÝø8¹aH1Foð xD÷÷ñø¤à ñD Oð
-EHF’l’<ðÈø"FÍø
-þ€F0F÷÷ýF(F8ðþF¨;ðGû«
-@òÉ æ÷þº@òŸæ÷úº@òË æ÷öºOô3pæ÷òº
-
-à$à$à$à$à$
-à+h£BÐ FðRø
-¹ 8à hq¹FðÚþàðøþFP¹Þ#
-F
-Ñšø ±(`"`àg"àu"
-àOô€J»ñ
-Ó@ò
-K"%F{Dð²û à9F
-³F
-0ðŽüFP¹K#
-#C`F Fh+ Ü€h±ðGü ð3ü `±
-+ Ñ
- ðñüFH¹ #
-#c`0FÜ÷pü
-F€h!hÜ÷ ÿFH¹¿#
-Oðd ~D à) ÑÔ\Z,Ð+,Ð-,Ñ
-à¬ñ1aàÄ`à„`àD`
-Oð< OôajüD
-ûô ûD1³ )ÖѱMç
-K"%F{Dðèø à9F
-K"%F{Dðø à9F
-¹p$à¡h¹<ðþàSÉÆSBÂë Éöà³T:‹\¬ ë
-#F‰“Dà ø ;Ê\ ë
-ë ¹
-F€h!hÜ÷µúFP¹Oôës
-Xp p h3 `pG hp ØpZp
- šp h3 `pG-éóNF FFFAò Aò
-Aò /àNEÑø;=“"àVEÑ"x=cx4Cê#“à^E Ñcx="xCêcâxC¢x4Cê#“à F)Fª:ðËý
-™¸G
-೿³ Ðz#
-àAò$àAò$àAò$ºñ
-Åø
-à F
-ÁEÑ9F(F2F
-±<ð
-ò
-Õ h±ðBü`h±ð>ü
-h2±“ù<
-Ñ0F!Fšÿ÷lÿp±›+` àg"
-hhhÀpGhhpGiÛÕðb»pGK{D`pGâ²
-N~D0hH±©"F;ðŒû ±0h™;ð—úF(F°p½1ÿÿÿN!
-Ÿ|D#h'ð#¹%HxD;ð ú `#K{Dh<¹ò#
--Ü‘à)Ñâ\Z*Ð+*Ð-* Ñ
-üDæ\0>ò² *wØâRx¢ñ0 /qØû&3«B¦ñ0jÜ\ø!pºBfÛ ñ Wø!pºB`ܸ±O/Øßèð 
-Oð< OôajüD¦\0>÷² /&اx§ñ0 »ñ Øûv\ø#p0>¾BÛ ñ Wø#p¾BÜ(±+ ¿
-ûñ û32+ÛÑ ±àFSXBXA½èð
-ñEêÉà F
-FñûÑoð
-KA"{Dðþ§`@F à%`F± h±1F*F;ðYü£h
-±h|¹ÿ÷ÿFH¹F#
-h°ˆFðF ’
-ëðåÿƒF@¹@òVC
-àF Fðý
-•Oðÿ5
+ü÷vüF¨d ü÷aü«l Q/HšYxD`
+g
+€çIyDòçxH
+ë
+(FyDDðRúDIF(FDð\ú;",*TIF`DðFú0ø
+%)¿0l˜Pø'»
+0FšYF%+Oð
+
+0³¹¹ñ
+
+ `
+0Z`rlOðRø
+
+’ü÷jú
+š ›Bø
+
+ñOê‚Aø"0AD›Aø<»ñ
+0˜DHø¼P1ç")Ð') Ññ XFGð“ÿF±
+®¶ùL0
+%
+éçØø
+àDê $âçCê#îçõ€g9Fü÷jù»EøØ,
+ù F½èø@ü÷¹3êçÕ(hü÷þø3x[Õhhü÷øø5åçø½
+à0D£k@h˜BÓãk˜BÙü÷Ùø6 l…Y
+à°h8±£k˜BÓãk˜BÙü÷Ãø 6sh
+»h ±ü÷®ø#k3Ñàjü÷¨ø`k±ü÷¤ø`hÿ÷ÿ£ŒZÕ hü÷›ø£ŒÕ hü÷•ø F½èø@ü÷¸#Rø#3
+ëSø|68FGð—üƒF8Fû÷EÿkhJø
+fSø* ’]PÕbSø"
+‘ÿ÷6þ
+™F ›Ãb)¹ßø%zDÿ÷.øŠá
+© ¨ÿ÷ãü š
+›`c¢cÑ;ác
+Cð!ý(D Ýø,€˜ø
+ëJø
+ë
+ë š“Jø Ýø,€@FCð¡üë
+ø± F °½èð ›(FpFð÷ÿ8± ‚I(FyDCð´û(D 5F©çI"(FyDGð5ú ¹|I0yDCðÅû¹ zJzD‚æƒ “ƒx>+“Ð
+ñ  Fÿ÷×ýsçiJzDZæhI"(FyDGðüù‚F
+çç]+ðÑ9FpCðKû0DCx>+èÑ[!(FGðïùEsr)F F “ÿ÷ˆø
+³@h
+(KÍø
+HFÍéˆð—øPF ñð’ø3hBFÍø
+ñ)F@FØG `(FBð4ý£h#»™ñ (FñðeøAF(FðGü™ñ4@Fñ,
+ðYøQF@Fð;üÙø AF(Fÿ÷£ü `0FBð‰ý°½èp0FBðƒýøç-épOF°ˆFF±
+ñ
+
+ñ,
+“› “ «é
+­“h(FÓø  Bð†ýñ<ZF“ñ“IF+FÍø
+3Òø °š “’ðšùš ± › “ñ< ®“ ñ(
+ñ!F“@F3FÍø
+ðxù ›è`+aPFBðaù›ç
+)OF FD!ØÃhs±
+K,aä
+DõçF½pµFF
+Ùêh1FëÄRø4 4[hAð°þñçp½-éðO‰F‡°’FFªQFHFAðæùx³™8Fÿ÷™ÿFH³
+ü F½
+º 0ÿ÷º€h$0pGpµFF£hF)FbhAðüýñ )F #½èp@ðºpµF0 FFÿ÷ú@±ñ 1F(F #½èp@ðºp½øµF
+#)FÍé
+D
+I
+KEh{D3`-±(F
+ø F½-é÷OFÝø0€FŠFFø@ @FÝø4°ÝéE’ÿ÷kÿšX±ºñ$Ø#ú
+óð Ñð6Ðb±Íø4°2FÍø0€;FQFHF°½èðO
+Öé
+¬ÍéR
+“›3Ð FAð%úh[EÑÝé#1F•—Íé#Oðÿ3“Ðé#@FÍé
+ FAðîùÓçoðF
+Ð šKE¿ZF ’ ñ èçÍø,°ùçÚF÷ç.
+çoð
+¯BF)F8F@ðqÿÝø(°@K›E ÐIH@òëxD
+›[EÐ
+›CE±Ñ3hJF)F8FÓø€@ð
+Xißø ùDØøB'ÐÐé
+F)F¤F0¼`G0¼pGD
+
+bÄaLjÊaDbJb0½Ê
+iih`KiCa‹iƒaËiÃa jbKjCb
+6Óø
+?ð²ü3F:F!F
+HxDÕ0ÿ÷Cü F
+š¦ë
+ëi&hÓ“›D›»BzÙëhRF1F FÓø
+ÿF
+D¨B'ÙšB ÒH@òV"xD
+Iÿ÷>ÿFP¹
+H.F!hxDº0ÿ÷ùoð
+;`¼ç
+àI@Fÿ÷&þFHxD
+Iÿ÷´þF
+H1hxD
+ªÍé #ª
+“Øø
+ú›˜B ÐH¦"xD
+h
+Ò‘BÓF"FCð+ø+h #D+`8½
+óç KYø0F“?ðžùF F>ðìþ"h
+ÒK…"{Dññ=
+RFHFÛh˜GØø
+Ûh˜G™ >ðÿ #0`Èø
+’
+^hÙh#“"ich1DÍøDÍø
+°½èp#i¢h3“BØ#akh‹BìÐH˜"xD
+°½èp˜ÿ÷øü(ôÑ
+Ñ`; +Œ¿oð:
+ð ¸îó
+ðƒ¸
+ðc¸
+ðƒø.`÷çoð(
+D“BÜ:“BÚ¢õÈr“B
+
+$›!hðuù
+ ªI0FÍø, Íø0 þ÷¢ùعoð>†çÚød0™Øh?ðþ
+¿Oð
+¸çOð
+µç š€*
+ñ
+ºñðÑ›8FYiÿ÷‡ûF
+ç ñ<AIBF8F””þ÷ùDK0FÝé«®<IYø0””3”“+h”iþ÷ù–RF[FÍø
+F
+« ’ ’ ’EJ
+’"ø0 ª’è
+
+FCø
+ œþ÷3ÿH¹ ð:ýF¨>ðÅÿ F°ð½
+ý›8`Xhðø›0`˜hð
+FCø
+KµF†°
+ ¹ ð:ü
+›FS±
+˜&ð¢ÿà ð0ü ›F
+™ F@ðnû
+I@Fý÷Žû
+°½èp«"F„IPFý÷ñø
+ÐBH
+3`Óç5I˜ý÷½øF ¹2I˜ý÷·øFØø ºñ
+›)F0F
+ÐH*F !xD
+øF¢çè
+JFSF!F0F
+"xD
+« “1FK ”
+”Xø0Íé
+ø30ø2  ø1 ø00 ›“ðûF
+ëÇZø7 FZhð¿û
+M{D3`}D
+FFIü÷'øع"FI0Fü÷RøX¹HxD
+
+­(Fñ÷üª©(Fÿ÷ÿF@»š(FCIü÷}øH»™(F
+
+”
+
+@òÉ á÷Q½@òŸá÷M½@òË á÷I½Oô3pá÷E½
+
+JµF{D›XñFCø+Ã`
+“«FFIXF“û÷Ôù›°±ªOðÿ3Bø=HF@Iû÷Éù2h»0FÒiG(›.Ñoð4*`#`àF6IPFû÷¶ù
+ñ@ø¯#bñcbú÷?ü Fñ@@ø<¯ñ,£dñDãdñp
+ú÷0ü6KPFÄé*‰{D\3#`
+à)Ð )Ð)(ÑŸ*J¿oðàd:*ÏØK{D3ù F8½p*J¿oð%÷çe:*ÀØK{DëB²ù: íçi:*¶ØK{DëB²ùh ãç HxDú÷Æùªçoð(Ûçoð%ØçoðÕç
+@òÉ à÷¾@òŸà÷¾@òË à÷
+¾Oô3pà÷¾
+F
+M{D3`}D
+3
+«F“ÿ÷‘þFh¹›IF˜h›h“Íé
+˜9ðÍü
+˜0±:ðHúà ÿ÷SýF0Fð¥þm¹¸ñ
+Ú
+¬ ”
+”¬”¬”Íø
+#«Éè
+›cgKòXKåg2Äø€P¢gÄø„PÄøˆPÄøŒ€ÄøPóX3#`°½èp‡
+üéç
+F
+H•"xD
+ø2ðøi+ؽè@
+H!FxD‹0ù÷Éûoð
+H½"xD
+Oðÿ0 `óçÐø
+hh#*i
+Ü þ÷†ýF8Fðû F°½èð"F9F(Fÿ÷ñûF
+ú÷RùkoHøM+
+Ñ™ˆBÒZF@Fÿ÷:ýF€¹Ýé
+thSF1iJF
+Ü þ÷øüF8FðŽú F°½èð"F9F(Fÿ÷cûF
+ú÷ÄøkoHøM+
+Ñ™ˆBÒZF@Fÿ÷¬üF€¹Ýé
+thSF1iJF
+°½èp+h(F™j˜G
+®0Fî÷¶ÿªIF0Fù÷¡û€F¸¹"h Fih’jG«Íø€Íø$€Cø0 “è
+®Ûj˜GF»#h F™j˜G
+X
+Ü‹#®"
+òø ED
+ê
+ø  hÄø
+«ð'þÕðfúÀó
+DíÑK¨ë ™E˜¿OêI ¸ñ
+0ðýF`¹K#,F
+#0µC`…°F Fh+ Ü€h±ðÀü ð®ü `(±"
++Ñ
+ ðœýF`¹ #F
+Ñ,FÓç
+#Ûç `¡h0FÔ÷;û `Êç Fðyýðç
+FFh€hÔ÷ÁúFX¹¿#F
+ þD ññ$ø¬ªñ0
+_úŠó +äØø<£ñ0 ,ÞØ û
+:”¥Bªñ0×Û^ø&p»BÓÛXø&p»BÏÜ
+û#0; +?÷b¯8³OôabZCóx0;Þ² .?öX¯ø`¦ñ0 /?öQ¯
+'ûc0;;+?÷J¯±<&û"4
+›zD“ ›“ ›“ ›3
+ÝD-óç% Fð`ú(F°½èð
+€¹@òF
+FFOêásÛ½è@ÿ÷»¿JBcëCÿ÷¶ÿ± Oôsc`½ðµP³Ch³õÐ+Ñ
+FFh€hÓ÷=þF`¹@òÛF
+®JF™0F
+áºñ
+Ñ ™Oöÿb‘BÑ—#
+ñ
+9ð½ýDhç ›
+Aò$¯X»ñ
+Aò$¯XÏçVJAò$¯XÉçSJAò$¯XÃçPJAò$¯X½çNJºFOô€X $¯X¶ç F
+ñ@FðøFˆ¹ú#A"
+F8FP!ÿ÷çÿO(F Ý
+I "yD×ç@FðýóçOðÿ4ðç
+Ú«#
+ÑÐBÐù
+Ù¥ñ Û²+
+Ø&úóð¿"ð€¿$ßç"øç äç âçûÿ§h hhhÀpG
+@Fÿ÷rÿF%ð » ðÁúF ¹ù#
+Ù IyD@FðÂø:F±h@FðÕøÞçIyDóç±+h£BÅÐ FðyýÁç
+,ùÝßø`Oð
+ h
+ø<0;Ú² *çØø,¢ñ0 .áØ û#¼B£ñ0ÚÛXø.`²BÖÛZø.`²BÒÜ@³ñÿ6.Øßèð),.02
+!çç1;aöçÂ`ôç‚`òçB`ðç`îç++?ÑOðÿ6ñ dEÝoûx0;Ú² *‰Ø:y¢ñ0¾ñ ƒØOð
+û#0; +?÷|¯@³OôabZC{y0;ß² /?ör¯ø P¥ñ0 /?ök¯
+'ûS0;;+?÷d¯±<%û"Ï
+›zD“ ›“ ›“ ›3
+šFj³Ðø
+Üà
+h‰hC`ÿ÷¶ÿ
+±hŒ¹ÿ÷ÿFX¹F#F
+o
+h€F‰F ñ7
+®ð«Fø-
+“
+˜ÿ÷ÿFP¹@òMCž"
+Ð@òƒ3¤"
+
+'Jø= ñ7
+“«ø7 “
+› ˜ÿ÷ØüF˜¹@ò Cž"
++Ñ@ò33³"
+Kø=«h
-›37Ñ
-“iÑ
-
-”Íø  ¨ “ «
-F›Íø°•“ ñ%Íøÿ÷@ýF@¹@òú#
-š¢ñ+ÙÓbѹñ
-F ñ' ¨”Ýø8 ÿ÷êüF8¹@òö3
-ä
-* Ñ@ò3
-›ÿ÷Ëý
-BÑ
-¬hOð
-ç0FYF*Fð”ú$áaØø
-FÍø°—ÿ÷˜úF@¹Oô»s
-’ÿ÷ú¨±ø6@D¹@ò©
-˜Â ›› “
-˜Â ›› “7
+›"û
+6ëhSEÝ1F Fðý ›YF š“›“#
+ñ
+äç
+
+˜CE¿3h
ñ
-ëhŸB­Ûø60s±¨ ™ÿ÷ÌùF@¹Oôès
-Ð!F0Fðú!F
+ç› šš ›› “óç¨ÿ÷Tú
ñ
-9ð*ø7 à@òé
-F“ ñ/è"
-¨’
-F”“ðÀ“ ñ&Íø€Íø°þ÷ëÿÝø, F@¹@ò&#
-š+Fÿ÷žþFP¹@ò1#
-›Áë
-Éø&0
-‘c±@Fþ÷¡ÿF˜¹@ò9#
-à0F)F8ðþ
-±KF.à"FKFÿ÷‚ÿƒFíà
-Àòƒ€ÐÝø°€à¹ñÿ?Íø ¿'ðÀOð ¸ñ
+ FñðÀû1F
+@F8ð¿úX±@F8ðÖû!i PF
+ ›
+¨“ ñ'
+àC Ðø'@l¹Oôsx"
+š0FÝø,°ÿ÷†þF(¹@òF#
+›£ë 
+“Ù±+Ü@òN#™"
+ÑÚhÒÕš±š`
+äçºñ
+ô
+#îç¹ñÿ?Íø°¿(ðÀOð ºñ
+àyÐÐðÀÌçOð Öç›—“Oð
ñ
-’
-Ðx
-ày¿ðÀ
-ô
-™
-!F
-¨Oðÿ3
-ñ
-9ðKù › ©
-ZF
-¨Hø <›
-›Hø Hø<(Fñ 9ð"ù‚E(FàÓ9ðùOKF "8Fñ Oð
-{D9ðbý#h “àXø,Xø 
-±9ð¸þXø<
-ñ
- šñ Ó “(F9ðüø‚E ˜éÓš `*Ð8FðZùHFðWùàAFÚø (Fñ9ðù
-àºFOð
-àFà
-
-@±àiæç½è@ÿ÷Í¿
-+Øßèð 
- þ÷¸þ÷*¸K{DT3ÿ÷rºÔŠ
-ˆ
-±9ð÷ù*hchÓ+`&±ch3`à
-h‚BÑ1à31³BöÛaiåç@ò
-FA3ê
-:€ð/ɲÒ]!C%ê€ð=0
-CY2ê&(¿>"!ê2ê%
-bp à"2` 
-"pcpà  0`#p
-¹2`p½F!ÿ÷¢ÿ
-#+T
-ÚHÎ"IKxDyD{D,ð®ù,ðÀù0`p½ Â
-žF F‘F˜FÂø
-²E
-ÙÀF2F08ð“ÿ#hž&`½èø_³ÀFRF08ð‡ÿ(F0"!ÐDÿ÷Oÿ
-"+Äø
-
-Oð
-+àø¡ñ Ú²*Ø[² úòK@ó¹”ø40±à"h 2*q"`Ñ@F©ZF“ÿ÷Zþ›¹#„ø50à#`›í˜D+˜¿„ø4VEÑÑ
-à8F© ëÿ÷þ@±š*DDÐUEÑ5à
-Ø[²úñK @#±<
-Kr"{DðŒÿoð
-Kr"{Dð_ÿoð
-Kr"{Dð1ÿoð
-Ã`pGÀh
-Câ`½µˆ±h ±[j[¹Oôs
-!Fÿ÷cÿ
-F
-NŠB4¿F F~Dà(F1Fÿ÷êþ(ñÿ4Ñ
-:Fÿ÷Äý¸BØÑ
-HµxDð{üK H{DhxDÿ,Ö¿bOðÿ4`ðpü F½
-àJ±8ðíúà#¹ti±0Fÿ÷Ýý Fø½þÿÿ-éðAFÐø€F Fÿ÷ÞýØø
-*ñТBF÷Ñ8F)Fÿ÷¬ÿ
-Ü)+ÐÜ)Ñà).Ð) Ñ:àr)/ÐÜ
-):Ð )Ñ:às)-Ђ)Ð
-±8ð™ú
-àK±`à€h½èð²`à(h½èð ½èðÃh-éóAFˆFÅiš Õ­#
-F
- ð{Dš\[\pCppG ·
-"ø 0ø0ÿ÷Øû
+»ç(F7ðZþ(@òÖ€(F7ðTþ #XCð ùF
+8Fš6
+6šHø <›˜
+›Hø Hø<(Fñ 7ðþ†BáÓ(F>F7ðþ\KF "8FOð
+¯(F7ð|ý†Bÿô8¯»ñôŽ® Fþ÷ù›
+«“Fç{ô¢®›“#¦æ
++ÔØ¡Qø#0DG
+i"±Òh±]øKG FF]øK›ç-éñO FFFH³ x ±h*³*i
+ëh û¡CEÄÝ
+h-éóAF FðÐh
+ü„BÓ0F7ð,ü
+BÑiêçÏç
++%Øßèð$$$$ $$$
+Õ@ò3BÐ
+ ý÷N¾ý÷l¾K{DT3þ÷¿l
+¾‚|
+i:±ShðÐhhDpG
+hB±Shð
+DšBLÝ¢õ¨20¢õÀr×øÀ*L}i¬ñ  ñÿ<ƒû«ÛOêk®ë£ëOð ûÃ@òo ûóƒû‰Û@òµTÃëi õÑSõÔUsD5 D DIcCH¿3 룅û‰í¥ëiëDH¿4ë¤ûhD¤õúDK<$]¿
+› 4`
+:X@
+jp°½èð"2` 
+*pkpõç  0`+pðç
+FFF™FÂø
+Ù.KŠ".I.H{DyDxD+ð8þ+ðJþÄñ0
+ªE
+Ù4*FF D7ðTû3hD5`½èø´±4FRF D7ðHû0"8F1ÑDÿ÷tÿ;¥ë
+_D
+"Æø
+/-©ë
+ر*F07ð+û$êät5`Èø
+ñpƒø ,¿#
+¹2`p½(Fÿ÷,ÿ
+"C*T
+ ñ 3DžBÑ
+¥ñ ¥BØÈø
+F(F1Fÿ÷¶ÿ
+ðTü F°0½("
+ðüoð
+ðÚûoð
+ð®ûoð
+FFFÿ÷ο8µF FF7ðAù!FF(F½è8@ÿ÷Á¿µp±h ±¤id¹Â#
+ðpûoð
+Ã`pGÀh
+ðëú
+!ÿ÷[ÿ
+F
+¹bpGFùç±j
+ðº
+"6ðvÿTEÑ0hð
+ü²çAòèç¤ë
+ZE Ù,K@ò½+I,H{D3yDxD+ð6ú+ðHú1h@FQDÿ÷Öý¹Éø
+³õ
+Ò¼B(¿<F!F0hðêû
+ë3’xœBBê +÷Ø»ñö`¯ñ
+?
+HµxDðeþK H{DhxDÿ,Ö¿bOðÿ4`ðZþ F½
+-¡ë
+)4Ð )ðÑ ïçs)(Ђ)êÑja÷ç`h
+ðkøOðÿ4 F°½èðÿ÷Pý5hoð
+ð%ø F°0½m
+F
+ ð{Dš\[\pCppGC;
+"ø,ª˜ÿ÷úû
š+ “ñ
-’Ñ|#˜ø 0©
-#"ø!0ÿ÷¢û
-"ø,ª˜ÿ÷rûÀCÀà
-)'Ð )CÑDà)Ð܉)ÐŒ);ÑàŽ)Г)6Ñ à i½ h
-Ù˜FC¹.H@ò.I.KxDyD{DÁçFF£h%iòªBÙ*H@ò)I*KxDyD{D²çâh`i›«B(¿Å뚪BŒ¿Ãë5F%±À9F*F7ðÀþ£h"ië“B£`ÙHOô”rIKxDyD{Dçv/DÌÑ@Fà8F
-à8Fþ÷÷ÿ0Fþ÷ôÿ
-Ú#
-Ð F×÷Ëø"FF¨
-x
-¿OðOð
- 7ðJþÁñ %F )¿
-IÚ÷ù¹
-Ût#
-Ý H›" I KxDyD{D*ðþ*ð"þ s`½èþƒq®
-Ð ëðgDÀz pøz`p4 :ñçÑ;9
-!7ð ü01¨É²
-!7ðsü?Fиñ
-Ñ F1ÿ÷.ÿ±+x-+Ñà
-£p ±
-Óa#
-Ó‰#
-KE"{Dðùú
-Óµ#
-±7ð|ø"h›Ó#`
-ÑH±¨
-ÐOHt"OIPKxDyD{D*ðåù*ð÷ù¹õ
-ÕðÀÑ0Fÿ÷Uÿ±&ð .F
-
-Ó¢û EÎC ûUËßC¯B¿¦BÒ
-OðCëÊé
-;«BùÓ#±ss
-HQ"
-I KxDyD{D)ð¯ÿ)ðÁÿ{±hðuø hðrø
-kh±2{BóÓ¹`l`à+h"Zsà ½èøƒ
-àOðƒ&àOð‚&àOð&ñÿ9
-I KxDyD{D3)ðˆþ)ðšþ€À½
-FRêôÑ»ñ
-ðÔ1¹(Ùœù0
-®
-àJH*"JIJKxDyD{D)ðŒù)ðžùfx•¥x-Eê%&x5CæxEêefy•¥y-Eê%&y5CæyEêefz•¥z-Eê%&zäz5CEêd”œXÐœx]x$Dê$x,CÝxDêd]y”œy$Dê$y,CÝyDêd]z”œz$Dê$z,CÝzDêd]{”œ{$Dê${,CÝ{Dêd]| ”œ|$Dê$|,CÝ|Dêd]}
-”œ}$Dê$},CÝ}Dêd]~ ”œ~$Dê$~,CÝ~Dêd ”œ]$Dê$Û,CDêc “«¬
-ºðºÛ÷²¾Û÷¾Û÷k½Û÷º½Û÷ø½
-ÙKHP"KIKKxDyD{D)ð<ø)ðNø›
-à¨AF"Ü÷<ý
-ñ
-#›šEåÓt±š
-®ˆF‘F9F"(FšF—5ðÌý0F™ "5ð¥ýÔøø0 —¯
-ÐJ#
-ë<r¬ " Fõ€yõ¸x
--BêbOê#öÑ*F¨!Fç÷¾ü
--BêbOê#öÑ*F!F¨ç÷­ü=™ "¨ç÷¨ü¨QF2Fç÷£üoð›ð?Ð F
-Ðß#
-ÐÄ#
-±5ðö»pG-éðO‰°FŠFFFhF"
-ë3
-«©ëÄ
-©0F"
-¬ÿ÷•ÿ•øü0ñ
-àk±+ Ð@ò>#
-ëZF¨ÿ÷ÿ¨©"â÷Éÿ%ð¨IFBFâ÷Âÿð
-Ð
-Ÿ ž ÐOôAs
-à¸ñ 
-Ð@ò 3
-– •°½èðAÿ÷“¿
-àT›+ Ø@òÝ#
-Ùv#
-ÒÙ#
-ñ
-0à
-ñ
-Oð
-+ê SDú‰õ[D¶ø°›²ñOêS:ZDJêÃ
-úŠú ê
- úŠóJD(ê
-
-ë
-úˆøOêØ"BêHúˆøúˆò¯Ñ¼ñ Ðð?¼ñ¿''1ø€DD¤²ð?1ø€ED­²ð?1ø€CD›²ð?1ø€BD’²ŽçDêDCêC`C`½èð-éðGOð hñ~'Dh•² £²$ OêTú…ùOêÓ
-HêÄ$)ê?ÈëêÈë¶ø
-Êëê
-Êë6ø¬ÊëOê’
-›²Jê‚2ê
-#ê ÉëOêU Êë6ø¬IêÅ5ê Êë’²"êÈëÉë6øœ¦ñÉë­²³Ñ¼ñ !Ðð?¼ñ¿''1ø€Èëð?1ø€¤²Èëð?1ø€›²Èëð?1ø€’²Èë­²ŽçEêBCêC`C`½èð‡-éðO…°ž FF™F˜¢ñ
-·xqx3x?Gê! C
-ix+x•øàBê")yCëxBêb«yW@—Cê# Céy5CêcIFX@¨ÿ÷³þŸ˜'p;
- qcp; £p;ãp
-cq £qãq4ºñ
+’¶Ñ@ö|#"9F˜­ø 0ÿ÷Ãû
+"1F˜­ø0ÿ÷šû
+)%Ð )ùÑ à)Р܉)ÐŒ)ðÑ hp±ch
+Uø› F+FJFÊø
+x
+¿'
+ØG%F±4´ñ
+¿
+Ü«hšB<Ý Kœ" I!H{DyDxD0à,Oð
+K”"
+I H{DyDxD*ð£ú*ðµúj` ²çÀ2
+F©
+Î÷ÕûƒF»ñ
+!(F6ð6ø010Fɲ
+OêÑéÑ
+«p ±
+K
+±5ðü#hšD#`òç
+ø8³ F
+ÐKKq"KIKH{DyDxD)ðnþ)ð€þš@öšB(Ðßø¡«“úD
+ñ
+HF
+'Áé
+ÐøÀ¬ñ0 _úŒó + ÙOð
+à)hh hÊT$
+îç+h"Zs
+KOôr I
+H{D3yDxD)ðû)ðûh{€hDhD½
+þ(±)F h"½è8@’å8½8µF Fÿ÷ýý(±)F h"½è8@…å8½Ch+±h™hQ`
+ÿ÷ÞýƒF Fÿ÷¼ýYFÿ÷ŠùPF ðyú›F
+`0½ø @ê"õç
+FŠè
+Õ¹ñ
+Øh¤D`Ž`±(F4ðûû
+°p½("
+¨4ðßù!F"¨4ðÚù
+›žÝø
+&–
+Oêue˜Dw@©DOê7WDD@¼DOê4Tƒê Oê3c¦D‚êDOê2bƒê Oê3Cw@DOêwgD@DOêtdE@Oê5U D¾D©Dêƒê Oê1AOê3c‹DD‡ê Oê7W
+Oê6V´D‚ê Oê2b’D†ê
+Oêvf
+#“±D D‰êˆê
+“Oê0cOê2BšD “›„ê
+Oêtd†ê OêvfDY@FOê1Q¡DŒD‚ê Oê2cD “›A@OêqaD›}@ˆDOê5E+DF›S@Oê3SD}@7DOê5e*D…ê Oê5ES@Oêsc(DD@œDOê4T¡D…ê Oê5e(D•D@
+˜Oêtd€êOê5E*DQ@Oê1QˆD…êOê5e*DQ@’ šOêqa‚ê
+“Oê6V7D‚êOê2b’D†ê
+OêvfôT¯›Íø¸2–8“›:•ÍøØ°5“›Íø¼€3”=“›;ÍøÜ 9“›ÍøÀÀ4‘<’1—š ™Rø# Qø#
+D™Aø# 3+òÑ
+3@+HpOê@OêbˆpÊpïÑ
+ÙRKO"RIRH{DyDxD(ðÌø(ðÞø.ÙNKP"NIOH{DyDxDñç›#¹'F8F°½èð­ ñ( (FÓ÷”ÿ
+¨ ðUúÛçFãçšIF(FÔ÷¦ø
+ÙK‰"IH{DyDxD'ðåÿ'ð÷ÿš®9FÍé
+« "™F3ðžûÔøøª –a±‘#F’AFÍé
+ðÛÿF(¹Y#A"
+F“U2
+*CêcOê!öÑ1F FÞ÷ïü?›
+F³T2
+*CêcOê!öÑ1F FÞ÷ßü "=™ FÞ÷Úü*FIF FÅñ$Þ÷Óüð?Ð*F
+ð+ÿ ±è#
+±3ðó¹pG-éðGˆ°oF€F‰FFF"8Fÿ÷ïÿø0
+cðø0´BÓ°½èð‡š8FQF¨G
+ðQ¾øü0-éðG–°F ñF ñ
+ "
+¯ðFOð
+ðÖýF
+¬›FFŠF F_™&ð FÙ÷‚þJFYF FÙ÷½þðÐ ñ"
+ë @Fÿ÷ðþ"AF FÙ÷Šþö
+ðXýh±@ò3
++ ÐOôAse"
+– •”°½èð@•ç‘ 
+ðx¼-éóAFˆFFFs±+ Ùw#u"
+ðMüF
+ðéûh±Oô¦s
+­Ah(F
+K{Dß瓪›9F(F“›“›“›
+— –•@h°½èð@Uçz
+ë
+ø04ë@+Ð¥BòÑ6Oð
+
+°½-éðC—°™F ›FFFž+ ÐOô‹s
+"ê ¼ñ VD·ø °D~ˆED­²2DOêÕ8HêEú…øúˆõê2D$ê2DTD’²Oê’6Fê‚6²²²)êê
+TD4Dþˆ¤²OêT93DIêÄú„ùú‰ô(ê ê3DCD›²OêÓ&FêC›²!Ѿñ!Ðð?¾ñ1ø`¿Oð Oð 5D­²ð?1ø`2D’²ð?1ø`4D¤²ð?1ø`3D›²7ø–çEêBDêC`C`½èð‡-éðCFhOðOð Dh7ø~o² ¢²$ OêTú…ùHêÄ$)ê¼ñ ¤ëê¤ë¤ëOêÒ¤²FêB2ú„ø(ê¢ëê¢ë7øl¢ëOê“’²Fêƒ3ê"ê £ë £ë7øl£ëOêU›²FêÅ5ê#ê¥ë¥ë7øl¥ë­²!Ѿñ!Ðð?¾ñ1ø`¿Oð Oð ¤ð?1ø`¤²’ð?1ø`’²›ð?1ø`›²­­²7øm‘çEêCBêB`B`½èðƒ-éðO…°ŸF›F¢ñ
+›‰Fxx=x<yEê
+ñ]@›\@
+ñCD*
+«ºñ
ñ
-ñ
-íºñ3Øßè
-ð,$ 
- qcp; £p;ãp
-cq £qãq;
-7p0qsp; ?³p
-÷psq
-+xiyOê KKê+*yKê ëxKêk«yÍø°Cê#IFCêy5Cêc““ÿ÷‹þšˆêš„ø
-„ø€ØFbq: ?¢qçq4›Fºñ
-ñ›
-ñ
-dS@š‹êºñØßè
-ð 
-ø<ø,<ø,< ø,<
-ø,<ø<Oê#†ø
-†ø€sq; ?³q÷q°½èð-éðOë …°F‰FFF‡hFë Oöÿzàñ(Oô€2
-Ð HŒ" I KxDyD{D'ðqþ'ðƒþD¨4ð±ý`p½(Fp½
-ÐZ#
-Ù÷¬þPFÛ÷ úë l`
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-(¿0$($Fø`¨ø0Û÷Yù6!¨"F4ð…û¨)FÛ÷‘ù ¹¨Û÷\ù
-Ú£#
-©ªèk›ÿ÷_þ
-«Ù÷ºü
- ˜ÐHD©ZF4ð—ù ñh0Fë RF4ðù› ñ( Fë
-ªÊë
-Ù÷‰ü
-
-ªÙ÷Ýü
-9
-Ð Hs" I KxDyD{D'ð‡ú'ð™úD¨4ðÇù`p½(Fp½
-Ð=#
-Ù÷ÁúPFÞ÷3ù@- Ù&HR"&I'KxDyD{D3'ð ú'ðú-±ñ¼
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-›AF:F(Fè
-F
- Fø<Pø;0Ù÷ û(<ÑÔøˆ
-ªÍø“ñ¼“”øü0“ «Ôøˆ
-œ0FÝ÷úÿ„BÐEHOô®rEIEKxDyD{D³ç ¨Íø
-™BF›
-F FÝ÷êþ
-”Ý÷±ÿ„B¿ë
-šð`ø ›D$ê
-z
-
-F FøPÝ÷þ¹
-F
-‹F7ЛóÊë«BÐTHÅ"TIUKxDyD{DàÍø
-ªÊë
-Ø÷Qÿ
-ª«Ø÷ÿ8³›šD Fë
-ªØ÷¬ÿ
+ñDø<*
+2x6ø
+ øL ø,* ø,* ø,"
+ ø," ø," ø,¦ç>ø,>Cê#ø,>Cø,>ø>BêBø>Bê"ø\@¨”
+CYFU@•ÿ÷!þœˆø
+ˆø@ˆø0+ ˆø0+ˆø0#
+ˆø0# ˆø0#ˆø0+
+=p<q{p+ -»p#
+ýp{q# $»qüq°½èð
+qy6
+ øL ø) - ø!
+ ø\EF ø! $ ø øLFÉæ" ;p"
+;pøL;*;p* ;p*
+;pø\4FMFƒç-éðOFÐøˆFF…°FF ñ ë
+Ó“›¶õ€?ªë£ë
+Ks"
+I
+H{DyDxDàç% 2ðFûl Fp½vþ
+Ð÷´ÿPFÕ÷íý@.Ù$KR"$I$H{D3yDxDÛç.±2F9Fñ¼
+š F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+›)FÍø€ F
+ëÐ÷Àÿ
+ë
+ÚŠ#u"
+­ñˆop+p
+“0F
+ë˜1ð¯ýÙø
+™RF0F£ë
+
‹phËpÃy qÈKqCh
‹qChËqÃz rC‰Krƒh
‹rƒhËrÃ{ sÉKsÃh
‹sÃhËsÃ| tCŠKti
-‹tiËtpG
-”pÄX3 +Ôpðѽñ@Ãy pÈKpCh
-‹pChËpÃx qCˆKqh
-‹qPø;Ëq1‘BéÑpGå÷^½å÷z»å÷Š¹-éøOŠF ™FF1™B.ØÖFø\°F´õ€4¿£FOô€{
-à1F(Fÿ÷|ÿø=6k@`ê
-™EÒFH…"FIGKxDyD{Dà‹B
-ÒDH†"DIEKxDyD{D&ð£ü&ðµü@)ÙAH‡"AIAKxDyD{Dñçõ€r‘E‰¿Áñÿ&
-¥Bñÿ<(¿Äë,ê 0FOêì|AF¼ñ
-à£B(¿Äëø3øÀ ê
- ê Iê øÀ2¢BëÑ F@
-è3ð¶ú. Ù>–fCà
-ø\ø,³™ "J¨¤ñ 3ðYù õ”~BFñ
-CJ«êT5¥B¼ÓFj¨
-F FØ÷þ
-F{D
-JzDx2ø‹ÕCx2ø0
- ÔørhQU5"x0øÔšBêÑ"xàBÕzH|xD àšBÑbxšBÐ4Ñç4ørhQU5"x0øíÕšBÄÑïçÕ{x¼;ø 
-#
- à@òI
-ð¦þàphAU5Q]
-ðOþíáßø4xDð¨ÿFX¹Oôs
-ð;þà@F!Fÿ÷2þF€¹@ò#,F
-ð(þ'FêáOð
-˜@òÿë ø  !Fù÷‡þ„øÿ¡ F2ðžü
-*Ð ¹à;
-àð ÐY\x›3ø@ F!×Ô3œx4øÀðÑ‘BêÑà‘BÊÑ àŒÕZx9ø 
-Ô3»çÿ÷Õü¡J‚FxzD2ø ð ú‰ù¹ñ
-ðîü
-ð|ü?àØø
-ð}üT±`h±ðRý h±ðNý FðKý
-
-K"%F{D
-ðõûà(F!F2Fÿ÷‡ýF Fù÷!ü(F|½
-ðÏû F2àG±%F,Fø ±2ðø
-
- ñ
-gcëÍé#ñ€rOêR`Eñ
-gÝé gÝéñ
-Eñ
-#ÝéE
-j-éðOÑø Ñø
-ë©iëiië©iOêiiû ¹ë©h)ð|I€ø
-ë¤aOê)*€ø Oê)JOê)i$ð|Dëab!ð~AIêˆ €ø ë¢c"ð|B€øOê¨#ð~C€øOê¨9Oê¨X€øHêÌ€ø€Oêl€ø€Oêl8Oêl\€ø€LêG€ø ÀOêç €ø
-ÀOêç,ÿ€ø ÀGê†s·Gs·¶‡sÆs.Ft.-†tEêDÅtåuåäEuDêÁ„uLÄuLIvAêAvvÁvBêƒwšBwš›‚wÃw½èð
-— û
-Ýø° ÃûšÆû
-ŸÇûšÂû
-Íé ™˜šŸÝø û
-Ýø¨ šÈûŸÂû
-Ýø@ +šÊûŸÝø° ËûšÃû#ŸÆû
-žÍé
- ™˜û
-šÝø Èû›Çû,žŸÃû ›šƒû#Ëû'žÆû##žÇû#ŸÇû#žŸÇû#$žŸÇû#žŸÇû#%žŸÈû#&žÊû#ŸÝø¬ Çû#(žŸÍé#'›‰û#Æû#žÇû#)ŸÆû#žŸÇû#*ŸžÆû#žŸÇû#žŸÆû
-#Ýø° žÈû#Æû
-#Íé# Ÿ(š-›'ž‡û«#ŸšÃû«›Æû«žÂû«$ŸšÆû«›žÂû«%ŸšÆû«›žÂû«&Ÿ-šÆû«.›(žÈû«'Ÿ‰û‰)šÃû‰›Æû‰žÇû‰*šŸÆû‰›žÇû‰+šŸÆû‰›žÇû‰,ŸšÆû‰ ›Âû‰.šƒûg/›#šÃûg-(›Åûgœ'Ãûg$š›ÅûgœÃûg%š›ÅûgœÃûg&š›ÅûgÝéEñ
-#ÍéEÝéEñ€tOêT`Eñ
-JêÁ ™ë
-OêakÝéIë ñ
-# eë"2@;@¨aÝé‚aëOðÿ3êaOð|B
-ê
- ê Ýé#²ë
-cë *bÝé#²ëcë jb1°½èðËh„F-éðO£°HhŠh iÑø
-•%hCŸ–ûûžŸûð žû
-‰ÝøX Åû
-‰Ýø Ëû‰
-žÊû‰ ŸÝø Æû‰žÍ鉅û
-‰Ýø Ëû‰žÇû‰ŸÍé
-‰û‰ Æû‰žÀû‰Êû‰Ëû‰Íé‰û‰Äû‰Æû‰Àû‰ ŸÊû‰ÝøX ûgËû‰ÅûgÅû
-g!Ýø ÀûgÊûgÍé
-gÝø€ Åû
-g!Ýø ÀûgÊûgÝøX Íé gûgÅûgÅû
-g ÄûgÀûgÍég!ŸûgÅûg Ãû
-gÝø  ÊûgÝé
-Oð|BKë Oðÿ3@@¸ë
-#i@êÅOð~@CëOðÿ1Íé#@Ýé# @cëÝé EÍé#ñ€rOêR`Kñ
-Bê ™ÝéE‹¤EëÝé#ÍéEñ€rOêR`Cñ
-
-Bê„ÝéE@’Oð~FÌø Oð|B@Ýé# eëêÌø
-ê
- ê Ýé#²ë
-cë Ìø Ýé#²ëcë Ìø$ #°½èð0µ©°FhF Fÿ÷zý
-¨iFÿ÷vý
-¨Fÿ÷rý
-¨!FF$ÿ÷ ú
-ªhFiFÿ÷ú¨iFÿ÷cý
-¨ªFÿ÷ÿù¨
-©ÿ÷Zý¨Fÿ÷Vý<ùÑ
-¨©F $ÿ÷ïù¨
-©ÿ÷Jý¨Fÿ÷Fý<ùѨ
-ªF$ÿ÷ßù¨©ÿ÷:ý¨Fÿ÷6ý<ùѨ©F $ÿ÷Ïù¨Fÿ÷*ý¨Fÿ÷&ý<ùÑ
-¨©F1$ÿ÷¿ù¨
-©ÿ÷ý¨Fÿ÷ý<ùѨ
-ªFc$ÿ÷¯ù¨©ÿ÷
-ý¨Fÿ÷ý<ùѨ©F1$ÿ÷Ÿù¨Fÿ÷úü¨Fÿ÷öü<ùÑ
-¨©F$ÿ÷ù
-¨Fÿ÷êü
-¨Fÿ÷æü<ùÑ(F
-©jFÿ÷€ù)°0½
-«ƒû
-‰ŸÝøX Àû‰Æû‰Íé‰û
-‰Ãû‰Üø\0Äû ‰Ãû‰Üøh0û«›Àû‰ÜøppÆû‰Üøl`ÜødpÆû«Üøp`Çû«ŸÄû«Àû«Íé«û«ŸÆû«Üøh`Æû«Üøt0Üøp`Çû«ÜølpÄû«ñ(Àû«ûÜød`ÃûšÜøh0ÇûŸÃûÝé
-#’CëÍé
-#ÆûÝé #Ýég’CëÍé #Ýé#’CëÍé#Ýé#’CëÍé#Ýé#’CëÍé#Ýé#’CëÍé#ëIë ¶Íé#Gëë
-ÍégKë Íé#AëÝé
-#Oð|JÝé ‰Oðÿ;Íégñ
-@êƒê ë
-Íé ‰Ý鉀aëÍéÝéñ
-
-# ›Ýé‰ÝéŸëIë ñ
-ê °ë
-#ègOð~@@ê
-ê ¸ëiëOðÿ9Åø€ Ýé#Ýø4€Ýé&–cëÝé #Åø„`Ýégê
-ê ²gë ŸÅøˆ ºÝégBêˆOð~HÝéÅøŒ Ýé#ê
-ê ²gëÝégÅø Ýé#êê ‚aëÝé
-ê ²gëOð~JÅø˜ Oðÿ;Ýé#ê
- ê ²ëcë Åøœ "šþ÷qþ(¨!Fÿ÷àù F!™*Fþ÷hþ!˜*FFþ÷mþ(F(©"Fþ÷hþ#˜!šFþ÷cþ3°½èð-éðCFFñ(‹°ñ(F9F2Fñx þ÷Fþ(F9F2FñPþ÷Iþ8F!FBFþ÷Nþ(F)Fñ(þ÷HþHFñPñxþ÷AþñPhF
-Fþ÷'þ F9F*Fþ÷,þ(F9F*Fþ÷þ8FiFJFþ÷þHFiFJFþ÷þ °½èðƒ
-kë FFÍé«ÆûOêPjMJêÁ •z
-«Æû«Íé(«Ýé «ºë
-kë FFÍé «ÆûOêPkOêajKêÁÍø4 
-kë FFÍé"«ÆûOêPkMKêÁ•
-kë ƒÍé‰Oê¡iÍé«CêÍø¡ÍøLÍøH€Ýé Ýé«Ýé(#Ýø€ë
-
-Ýé,«g’Ýé#"@+@‚aë™h’›š‰˜›Aê‚™“’Ýé‰Ýé$#‰‘ë ™i’Ýé
-¨iFzDþ÷#û2FhFiFþ÷û
-¨2FF&þ÷û¨
-©þ÷sþ¨
-ªFþ÷û F©þ÷jþ F!F
-ªþ÷ûjF F!Fþ÷û¨!Fþ÷\þ(¨©þ÷Xþ(¨Fþ÷Tþ(¨!FFþ÷ðú¨(ªFþ÷ëú¨Fþ÷Fþ¨(©Fþ÷âú(¨©þ÷=þ(¨Fþ÷9þ>ùѨ(©F &þ÷Òú(¨©þ÷-þ(¨Fþ÷)þ>ùÑ(¨ªF&þ÷Âú2¨(©þ÷þ2¨Fþ÷þ>ùÑ(¨2©F &þ÷²ú(¨Fþ÷ þ(¨Fþ÷ þ>ùѨ(©F1&þ÷¢ú(¨©þ÷ýý(¨Fþ÷ùý>ùÑ(¨ªFc&þ÷’ú2¨(©þ÷íý2¨Fþ÷éý>ùÑ(¨2©F1&þ÷‚ú(¨Fþ÷Ýý(¨Fþ÷Ùý>ùѨ(©F4Nþ÷rú¨F~Dþ÷Ìý¨ñ(Fþ÷Æý F©"Fþ÷bú F!Fªþ÷]újF F!Fþ÷Xú(¨!Fþ÷³ý(¨
-ªFþ÷OújF2¨(©þ÷@ú¨2©þ÷xù¨AF " ð@ü ±jF2¨(©þ÷'ú¨2©þ÷iù¨AF " ð1üè¹ F!FñHþ÷+ú¨!Fþ÷Yùøx0úð³ëÒÐ F!Fÿ÷øñx
-¨ý÷‰þx'‚ªû'
-©jF58F@6þ÷áøñ(
-©P7jFþ÷äø8FiF
-ªþ÷éø8F9FJFþ÷äø-ØÑ F?%ÿ÷ûñ(
-ÿ÷ûñP
-ûqþ÷Çþ õ´cP¨
-û:iFÿ÷YþPFP©ÿ÷þ-ØûpiFÿ÷5þRFhF1Fñ
-ÿ÷hþP¨iFÿ÷Cþ õ´c 
-0P©ÿ÷
-piFÿ÷þ5-ÇÑ F
-ñ(
-ê Íé#›˜ý÷äüB K BêÁbê ê
-ÍéEhý÷Èü„Dêtê ê
-Íé gŸøý÷ÈüÂ Ë BêAbê ñ
-
-Íé"‰ý÷ºü Bêrê ñ
-ÍéEý÷žüIOê0
-ê ÍégŸñ
-Íé
-‰ý÷‚üÄÍDêAtê ñ
-Íé #ý÷tü
-ê ñ
-ÍégŸñ
-Íé‰ý÷[üšÆ Ï FêAfñ
-ê
-ê ÍéEñ"
-ê ñ$
-Íé$Eñ'
-ñ*
-ê Íé(Eñ,
-Íé,‰ý÷íû‚‹Bêrê ê
-ÍéEñ1
-Íé‰ý÷Þû Bêrê ê
-ÍéEñ7
-ê ñ9
-ê ßø<Ã@êApÉ û # û3ë
-Gë  û#ÝégÍé*«Ýé«û3¶GëÍé.g û g ûwë
-Kë Íé«Àñ
-g
-û²ßøä²×Ýé$#’Cë û gÍé$#Ýé&# ûw’«NCëŸÍé&#ûs ûÝégYÝé(#CëÝé*Íé#¤û # û3¶Gë¤û#ÍégÝé.gû3€Aë¤û #Íé(Ýé û3¶GëcBÍé*g¤û
-g
-û2€DAë¤û gÍéÝé$ ûw€žAëÍé$…Iû3¤ûE]Ýé&#œCëÍé&#›£û  ûÝéE$Eë£ûÝé#ûCëÍé#›Ÿ£û Ýé(# ûžCë¦û
-Íé#sB
-û2Ýé*g6˜DgJGë™Íé(g û g ûwÝ逞AëÍé™û3¦ûžYÝé$#CëÍé#›š£û  ûÝég6Gë£ûû"œEëÍé$#›£û Ýé# ûœCë¤û
-Íé#cB
-û2ÝéE$DšEëÍéE¥û Ýé(E$<H û
-ÝéE
-û2$DšEëÍéE¥û ÝéE$H û
-#CëÍé#› š£ûûÝé#CëÍé
-#› šà
-
-
-û2Ýé g6D šGëÍé gŸ§û Ýég6¶H û
-€AëÍé
-YPAêÒ!Ýé#cëÝéÍé#õ€OêPRAñ
-ÍéEõ€OêRTCñ
-#cëÝéÍé
-#õ€OêPRAñ
-E$ ˜EëÍé
-EmB
-aÝéE$EëÍéE œ¥û  ûÝéE$®HEë$™ÍéEœ
-ÍéEUB•
-ûUiÝé
-E$Eë¢û Íé
-EÝéE û$˜EëÍéE†MûÝé¢û#ãÝéE¤Eë¦û #ÍéEÝé"E û3¤Eë¦û#Íé"EÝéEû3€AëÝé #Íé¦û  ûCë¦û
-Íé #sB
-û2$DEë¦û ÍéEÝé
-E û$˜EëÍé
-EcMû3¦ûEÝég]6GëÝé EÍégŸ§û # û
-Ýé EQ$EëÍé Eš¥û ÝéE$AH û
-EY$Eë˜ÍéE¥û #ÝéE û
-E¥û#ÝéEû
-#
-g¶Gë û #Ýé û 3ßø À€à
-#
-û Ýé«ë
-D˜Kë Íé
-«Ýø°«û #ëÀJ û
-Kë õ€OêPREñ
-E’cëÝégÍé #Ýé#õ€OêRPCñ
-EMDEêÐ%6gëõ€Iñ
-AêÒ!Kë ¸ë
-Íé#õ€Añ
-#ÍéEÝéEcëÝéÍé
-#õ€Añ
-CêÔ#Kë 4FÍé«€aë=FÍé"õ€Gñ
-EGë ßøD
-ûUÝé«£û  ûÝé‰ë
-Kë
-
-E$ÄHEëÍéE£û
-½Iû£ûQÝé#CëÍé#r {BêÇ"]ë
-kë BêÅ"_Íé ‰€OêBVGêÒ'Aë"FÍé«+FÝé
-E’cë€FÍé#B K‰FBêÁ"Ýé_¤OêBVGêÒ'OêTREë¸ëië BêÅ"kÍé
-‰€OêCWAëVKGêÒ'B ¢F«FÝéEºë
-kë BêÁ"_Í髤OêBVGêÒ'EëF FÝé ’cë FÍé#b k©FBêÅ"ÝéE_€OêBVAëGêÒ'KB OêC[BêÁ"¸ëië KêÒ+¤OêBZEëÍé‰F F²ë
-cë OêeYOêTXÍé #Ýé"#OêIWHêÅ(ëGêØ'OêHVCë  F©F’F¸ëië ÝégÍé"‰OêRXOêcY›FHêÃ(OêIQëOêHPGë AêØ!{r ºë
-kë BêÇ"Íé«]Ýé‰TEêÒ%0F9F@Nëßø¡Ië
-g’%N
-û w¡û«CëÍé#KBû 2Ýé
-gë
-ßøh “DGë Íég¡û
-g
-û wÝé«ë
-&FKë /FÍé
-«ßø@°¡û  û <Ýé#aDCëÍé#kb OêC[BêÅ"ëKêÒ+OêBZIë OêiS à
-
-gë BêÉ"ÍégYÝégPAêÒ!ÂFËF¶Gër ºë
-kë {Íé«BêÇ"Ýé«YPAêÒ!ë
-Kë 2F;FÝé
-gcëTFÍé#OêkSOêZR]FYBêË"¶AêÒ!OêBPOêVRGë$eëÝéBêÇ"{ÍéEOêBXÝéE€OêCYAëKIêÒ)B ²F»FBêÁ"ºë
-kë OêCY¤OêBXIêÒ)EëFÍé« FÝé «²ëcë  FÍé
-#kb ©F_ÝéBêÅ"ë
-GêÒ'OêBVOêZRKë ¸ëië Ýé"gBêË"OêkST¶OêCUGë{EêÒ%r ºë
-kë ]BêÇ"€EêÒ%OêBTAë2F;FÝégcëÍé #KB ]BêÁ"¶EêÒ%OêBTOêVRGë
-qû šŸCêB3šCê†{q³ »q³ žŸCê†CžCêÇÓqÝé#[Oê2{
-2ršsr{ žŸCêÂ3šCê»r3 ûr3 ;s3 ŸCê3CêLSsOêÜ“sOêÜ3Ýø,ÀCêLCCêˆÓsOê˜ žtOê˜#StOê˜CÝø4€7FCê‰3ÝøPCêÊ“tOêZOêZ:Ótø00‚ø Su3
-“u3 NFCêCOêYHCê@ÓuÃvÃ
-Svà CêA3Cê„“v£ Óv£ œCê…CMFCêÉwÝé#„ø€[Oê2OêY#bw£w1°½èð-éðO­õ_} FF !Pª-FFà÷¶ÿø@1¨¨#ðø@1ø_1ð?Cð@ø_1à÷­ýX©¨¨ "à÷+þ"F)F¨¨à÷&þ¨©`¨à÷Íþ`¨þ÷(ý€¨`©þ÷6ü€©-˜þ÷ù¨¨à÷‘ý-™¨¨ "à÷þñ ¨¨ "à÷ þ"F)F¨¨ÍLà÷þ¨©p¨à÷ªþp¨
-Íé
-«ü÷Ãù BêrêêÍégp¯ñ
-Íé«ü÷‰ùÂËBêArêêÍégp¯ñ
-Íé«ü÷`ù‚‹Bêrw¨ê ê
-ü÷cùOêÐP¨OêÑHêAhü÷Lù
-›š ûñû£ûEÝé2#MCëD©Áé
-›š ûñû£ûEIÍé4E5‘Ýé2EÝé4#œCëÍé2#š›ûñû¥û#Ýé2EˤEëÍé2E@¬Ôé
-œ ›ûñû¥û#Ýé4EˤEëšÍé4Eœ›ûñû¥û#Ýé4EˤEëšÍé4E œ ›ûñû¥û#Ýé4EˤEëL›@©Áé
-œ ›ûñû¥û#Ýé4EˤEëšÍé4Eœ›ûñû¥û#Ýé4EˤEëšÍé4E œ ›ûñû¥û#Ýé4EˤEëšÍé4Eœ›ûñû¥û#Ýé4EˤEëÍé4EM›<œ<ÛíCêDt7•
-"œ ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëÍé6E šœ ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëÍé<EH­Õé
-!š œ ›ûñû¥û#Ýé6EˤEë#šÍé6E"œ›ûñû¥û#Ýé6EˤEëšÍé6E œ ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëšÍé6Eœ›ûñû¥û#Ýé6EˤEëÍé6EN›>œ>[ m CêÄd9•
-*œ ›ûñû¥û#Ýé8EˤEë!šÍé8E œ›ûñû¥û#Ýé8EˤEëÍé8E #š"œ ›ûñû¥û#Ýé8EˤEëšÍé8Eœ›ûñû¥û#Ýé8EˤEëšÍé8Eœ›ûñû¥û#Ýé8EˤEëšÍé8Eœ›ûñû¥û#Ýé8EˤEëšÍé8Eœ›ûñû¥û#Ýé8EˤEëO›Íé>EFœF›Cê„t­8”9•
-$œ ›ûñû¥û#Ýé8EˤEë+šÍé8E*œ›ûñû¥û#Ýé8EˤEë!šÍé8E œ ›ûñû¥û#Ýé8EˤEëÍé8E#š"œ›Ýø Àûñû¥û#Ýé8EˤEëšÍé8Eœ›ûñû¥û#àÿÿ
-ûñÝé8Eû ªû#¤ DEë Íé8EG˜BêEbë .
-û
-ûôªû#û D˜#DCë™û
- ™(šû
-ûôªû#û D˜#DCë™û
- š û3ûôYûD¥û#ã„Aë)˜ÍéE™(šû
-ûôªû#û D€š#DAë›ûô ûD¨û#ã„Aë.šÍéE
- œ¥û ûóš û3ûôYûD¥û#ã„Aë)˜ÍéE ™(šû
-ûôªû#û D€š#DAë›ûô ûD¨û#ã„Aë.šÍéEœ¥û ûó š û3ûôYûD¥û#ã„Aë)˜ÍéE™(šû
-ûôªû#û D€#š#DAë"›ûô ûD¨û#ã„Aë.šÍéE œ¥û ûóš û3ûôYûD¥û#ã„Aë)˜ÍéE™(šû
-ûôªû#û D€!š#DAë ›ûô ûD¨û#ã„Aë.šÍéEœ¥û ûóš û3ûôYûD¥û#ã„Aë)˜Íé
-Eš(›û
-EˤEëšÍé
-E&›û
-Eˤ
-E)˜™(šû
-¥û#&ã€Aë'›
-ûôªû#û D€%š#DAë$›ûô ûD¨û#ã„Aë.šÍé
-Eœ¥û ûóš û3ûôYûD¥û#(ã€Aë)›
-ûôªû#û D€'š#DAë&›ûô ûD¨û#ã„Aë.šÍé"Eœûó¥û ) û3
-ûôYªû#û D€(š#DûôAë ûD¨û#ã„Aëªû ÍéE.ûô
-ûó ûD û 3Y¨û#†#DAëûóÝé:EÍé g û 3¨û ‰™DÝé:#õ€Cñ
-Kë ¤eëÝé0#Íé «Íé*Eõ€OêRPDªCñ
-CêÐ#Kë Í髤eëÝé6#Ýé6«Íé(Eõ€Ýé8ECñ
-kë Ýé8#ÝégÍé.«õ€Ýé«OêRPCñ
-kë Ýé#ÝégÍé0«õ€Cñ
-kë Ýé
-#Íé«Ýé«õ€Cñ
-EÍé@FIF¤eëÝé#Íé"Eõ€Cñ
-gºë
-kë õ€Iñ
-#½M¾Lõ€ÍégCñ
-€aë«û#Íé
-Ýé.û
-3¶Gë«û#Íégû
-3€AëÍé ¦H§IÝé0g«û
-3¶Gë«û#Íé.gû
-ÆóÝég¶GëKÍég›N«û#û
-6Íé#Ýé#–Ýég’–NCë“OÍé#«û#û
-ÌÝé«ë
-cDÈñ
-Kë ¨û#Íé«Ýé«û 3ë
-Kë ¨û
-Kë ¨û#Íé«û Êû ÌSDÝé.«ë
-Kë Íé «ßøı¨û # û 3Ýé«ë
-Kë ¨û#Ýé‰Íé«Ýø, ëcDIë Íé‰Ýø(©û#Ýé‰û
-3ëIë Íé‰Ýø(©û#Ýé‰û
-3ëIë Íé‰Ýø(©û
-3ëIë Íé‰Ýø(Éñ
-Èßø(¡CDÝé‰ëIë Íé‰Ýø(Ýø,°©û
-#Ýé ‰û Ìë
-û 3Ýø( Ië ªû#Íé ‰Ýé‰Ýø ëcDIë ÝøÀÍé
-‰Ýø©û#û
-3Ýé«ë
-Kë ©û#Ýé‰û 3ëIë Íé‰Ýø©û
-
-Kë ©û
-·J
-E¸ëië Ýé#Íé‰õ€Cñ
-Oê@RKë CêÐ#ÝéÍé«€aëÝé
-#Íéõ€OêRPCñ
-
-eë Ýé#Ýé"Eõ€Cñ
-‰õ€OêPRAñ
-¸ëië Ýé#Íé‰õ€OêRXCñ
-ûšÍé
-‰Ýé(‰Íø, Ýé
-«ë
-ßø´£Ië Íé
-‰ßø¨“¤û ‰
-ûšÍé ‰Ýé‰Íø4 Ýé «ë
-ßøŒ£Ië Íé ‰ßø€“¤û ‰
-ûšÍé‰Ýé‰Íø< Ýé«ë
-Ië Äñ
-Ië Ýé«Í鉤û ‰Íé‰ û™ÍøTÝé‰ë
-Kë ÝøHÍé«Ýé«û—Ýé&‰¤ûEë
-=DKë ¹OÍé«ßøì²ßøÜ¢ û E ûUëIë Ýé
-EÍ鉠û
-‰
-û™Ýé «ëEë Íé
-E«M û‰û™ë
-Kë Íé «Àñ
-ßø”² û ‰ û¥©DÝéEëEë  û ‰ÍéEÝéE û™ëEë Ýé‰ÍéEû¤Ýé4« ûë
-‹H ûÝ鉢û
-EÍ鉢û
-‰ÝøpÝøt€©û
-û2Kë ÝéEÍé«ËF©û‰û
-Ýø€Kë Íé «¥û«›DÝé#ë
-Cë Ýé2«Íé#›F£ûû£ûEë
-7KKë ÝéûU2O
-EKë Ýé
-ûUÝé«
-
-˜DKë Íé«û
-œ û
-«OêPRAñ
-#¸ëië õ€Íé‰Cñ
-kë Íé
-«õ€Ýé«Añ
-EêÒ%Kë aëÝéõ€OêPRAñ
-€AëÍé
-YPAêÒ!Ýé#cëõ€Íé#OêPRIñ
-Ië Ýé«ë
-»HKë £û
-kë ÝéEBêÁ"OêCYÍ髤IêÒ)EëOêBXkb ‚F‹FÝéºë
-kë BêÅ"OêCY€IêÒ)OêBXAë"F+FÝéE²ëcë Íé#KB OêCYBêÁ"¤IêÒ)OêBXEëF FÝé ²ëcë Íé#kb OêCYBêÅ"€IêÒ)OêBXAë"F+FÝéE²ëcë Íé #KB OêCYBêÁ"¤IêÒ)OêBXEëF FÝé²ëcë Íé#kb OêCYBêÅ"€IêÒ)OêBXAë"F+FÝé
-E²ëcë Íé#KB OêCYBêÁ"¤IêÒ)OêBXEëF FÝé²ëcë Íé
-#kb OêCYBêÅ"€IêÒ)OêBXAë"F+FÝéE²ëcë Íé#KB OêCYBêÁ"¤IêÒ)OêBXEëF F²ëcë Ýé‰Íé#kb YBêÅ"ëAêÒ!OêBPIë "FOêXW+FcëGêÉ'Íé#OêiSz@F“IFœÝé‰cCê×#€aëšÍéI§ûEûUëEë ßø`§û ë
-H û§û
-
-GêÒ'OêBVKë OêkSOêZR¸ëië BêË"Íé‰YÝé‰PAêÒ!ëRFIë [FcëÝéÍé#OêXROêiSFFBêÉ"OF]Ý鉀OêBTEêÒ%OêPRAë6gëBêÁ"KÍé gëOêCUIë TOêiSEêÒ%OêXRÝég‹FYBêÉ"‚Fºë
-kë ÝéE¶AêÒ!OêBPGëBFÍé«KF°Fcë¹FÍé#{r OêC[BêÇ"¤KêÒ+OêBZEëb k¸ë
-ië Ýé
-«BêÅ"Íé‰OêCY Fë
-OêBXIêÒ)OêZRKë )FÝéEBêË"OêkS°ë
-¤OêCWEëÝékGêÒ'b OêCYºë
-kë BêÅ"Ýég€IêÒ)OêBXAë"F+F²ëcë Ýé‰Íé#B KBêÁ"]¶OêBTGëEêÒ%{r
-†ø$0û ž ŸCêF3-žCꇆø%0» †ø&0» žCê‚C-ŸCêƇø'0Ýé#[Oê2s
-‡ø( ‡ø)0s žŸšCêÆ3-žCê†ø*0; †ø+0; †ø,0; žŸCê3-žCêG†ø-0û †ø.0û
-žCêBC-ŸCꆇø/0³ÝødÀ‡ø00³
-‡ø10³ Ÿ-žCê‡3ø`pCêʆø5p†ø20OêZOêZ:†ø30†ø4 Ýø` ÓFOê#†ø60OêCCê CCê@†ø70Æø80Ã
-†ø90à  CêA3Cꄆø:0£ †ø;0£ Cê…CCêȆø<0_êiOê8OêX#OêXH†ø= †ø>0†ø?€ õ_}½èð-éðAF’ø?0­öx=FFFðàÐ
-ú˜¨p©û÷åù ö˜˜©û÷¥ù ö˜p¨À©û÷ûù˜¨p©û÷Öù ö8 ˜©û÷–ù ö8"p¨À©û÷ìù˜¨p©û÷Çù õÏc˜©õŒ`û÷…ù*¨ú÷Ãý Fÿ$ú÷Æý>¨ú÷Ãý£W
-úc]Z²
-Fù÷ðúp¨)Fzªù÷õúz¨)FFù÷æú(F©Žªù÷ëúŽ¨©Fù÷Üú*¨p©û÷ù<àOßøD€DøDõ‹gõ‹hbôe¯ õÏ`*©ú÷xÿ õÏ`iF "ðÒüÐñ
-šô÷ þhFñ ñ¤ô÷þ ¹ F
-±Ãh`pGpµFFF±€hÊ÷‘ù¦`±àhÊ÷Œùå` p½µ ±h `
-±Ái` ±Bh`½øµF
-ùh`
-!Ê÷KúH³8F!à!Ê÷Dú³8F!Ê÷?úè±è€QF(h"3FÙ÷Æþ ±HF!
-Ñ£i0F
-ÙOôÁs
-þOðÿ0 àhF)Fÿ÷“ÿ
-©"ó÷¹þ
-K{Dëch˜Gø½/±8F1F*ð°ú
-
-KA"{Dðü à
+‹tiËtpG 8$1Pø/3ø,Bˆø,h
+ø,hø,‹BíÑpGñ8H10Ây3ø,ˆø,Bh
+ø,Bhø ,Âxø ,Bˆø ,h
+ø
+,hø ,‹BáÑpGÝ÷á¸Ü÷ï¾Ü÷÷¼ðµ5B2ØÖ³õ€ø,žFOð
+`` ð½Õ‡ê U@7Eê øÍU@‚ê ,êåu$êßç
+»B
+ÙDK…"DIDH{DyDxD%ðâþ%ðôþ‹BÒ@K†"@IAH{DyDxDñç@)Ù>K‡">I?H{DyDxDççõ€s»B6¿§õ€u
+FhF
+…ê Y¢B!ê¥ëOêáqƒêCê ƒê Lê ø0_úŒü(¿@5 êCêësø°Cê ø02Æç
+‘ ’“ªœ ÓÓK@òÒIÓH{D3yDxD%ð*þ%ð<þÑ÷ÿü°õ(Ff¨#Ð@ò¡#žB-Ð@.9ÑÜ÷ùú#'“OðÅK0F{D
+“
+úú‚E/ÐÁKOô¡rÀIÁH{D3yDxDÐçÜ÷ëü #'“Oð»K@ {D
+ ™@ê
+
+X@,êàp
+
+3³BËÑf¬QF F
+ X\ êCZT3ššBôÑñn癑B‰¿ š
+™ FÑ÷,ý+h F š%`Ñ÷€ûZçšó
+FDñxøo[
+FDÍxøo[
+Ñÿ÷Eÿ)F@Fÿ÷Aÿ
+K@ò1{Dx3ø ð ÐBx3ø Õ0òç0ðç
+BùÑpG^¼
+Ðn+
+Ðb+
+Ðt+¿ #ahKU5¼ç #ùç
+#÷ç#õçð
+­ !3F(FzDðŸúöI*F yDð&øT±`h±ðòù h±ðîù Fðëù
+@òÿ˜\ø !Fù÷¬û„øÿ¡ F0ðLý›C
+)óб˜BÐ6
+‰ÔèçFšç
+©Ùø
+™)±(F/ðþ
+˜ÿ÷Ëû
+K" {DðÏý(F°p½F2F(Fÿ÷§ýF Fù÷‹ùòç å
+ñÿ:(x0ðÕø
+š1 Fèç F0ð3û8%êç Çç
+Ð )ÐBh*±:™\ )Ð )ÐpG3:`B`éçB`ïç8µFF F0ðûbh‚BÑJ±)F h0ð ú°ú€ð@ 8½
+DÅé
+"9F(Fÿ÷¶ÿ8³Ýé”
+FF Fÿ÷½ÿ0±)F Fÿ÷gÿ
+JlF)F FzDÿ÷Ÿÿ0±I FyDÿ÷‚ÿ
+I(FyDÿ÷Pÿ±Dð F°0½Fúçuâ
+š9F0Fû÷wûñ¤ñ (Fû÷ƒû8¹ F
+­@!(F¡F×÷Zû(F ðyüø 0DêÃø @ ñ ¹ñ OêSòÑJF)F8F õz0ð‹ø¬9FPF ñ ð„û"Fó™ò˜EFÜ÷ø@"!Fñ`
+(F ð²ù)F†­(F ð©ø*F®­IF(F ðTù)FÖ­(FéF ðÚø*F­(F!F ðOú)FHFþ­ð"ÿ(FÛ÷SûÔø°0Ó»Ôø¤ (FÔø ÿ÷þÔø¬ (FÔø¨ÿ÷þ "QF(Fÿ÷þÝøð "(Fÿ÷ þIF "(F ñ ÿ÷þ@"ñ`(Fÿ÷
+ÿ#>` Äø´0„çJzDœçÔø¬ (FÔø¨ÿ÷äýÔø¤ (FÔø ÿ÷Ýý "Ýøð(Fÿ÷×ý "QFÃç@&Øç2O
+±Ãh`pGpµFFF±€hÇ÷ÿ¦`±àhÇ÷þþå` p½µ ±h `
+±Ái` ±Bh`½øµF
+!0FÇ÷°ÿ
+K{DÍçAF0FÈ÷pøF(FÈ÷°û(FÈ÷³ú©ç™Ù
+D]øKShG3+óÑ
+ÿ
+©(Fú÷û¸¹Þ#
+K{DÀç0Fú÷=ù
+œ‰FFF FÈ÷,ø FÈ÷cøF8¹
+ {Dðhü F°½0"
±Ci`pGµ ±Dh `
-±h` ±Âh`½pµF
-˜*ðvúë
-8¿Oð
-ºñ
-É÷wüÍø, 4à"©Ê\2Ò²ÊTR±š
-™Î÷îÿ
-
-
- K
-
-
-
-¯É÷{ø8FÉ÷xø¨É÷uøÉ÷|þF
-
-ñûÑ‚Ò‚BÓS
-ñûÑ
-
-
-
-
-
-
-
-
-
-
-
-þF
-x3
-©"ò÷•þ
-ò÷ïü"FF ¨ò÷Ûü¨ò÷çü"F¨ò÷ÓüÐ÷AøF
-û•¨,|ii"Fÿ÷“þ
-¨OêG"FADÿ÷þð±kië ¨"FYÿ÷xþ¨±iiOꇨ"FADÿ÷oþ`±kië¨"FYÿ÷fþ±(hÑ÷ü à6.ÂÑ@ò—
-©¡"ò÷Dý8¹œ#
-¨ ©"ò÷6ý
-¨ò÷ªû
-©¡"ò÷£ùP¹è#
-¨©"ò÷’ù
-KF{D
-Ú•#
-þ0FÐ÷.ø8FÈ÷ ý8FÈ÷TüàOðÿ4 F°½èð
-F¨Fò÷$ø¨ÿ÷ÄÿFh¹¶#
-ñûÑ‚Ò‚BÓS
-ñûÑ
-±GàFÏ÷ü8±Ï÷ûÇ÷Åý½è@ÿ÷Ê¿
-hÛ ³ëÒ?Ó”¿
-ðúùF ¹Oô†pð‹ûFp±!FOô†r(ðÿøJ F)FzD
-ðîù
-иñ
-Ð-Hê"-I-KxDyD{D@àNð1eÕøR±K±aX!¹&HxD``à`ª‰`ºñ
-F F ‘ÿ÷pÿ½µ F
-ðŸøK(F{Dhb`
-ð™ø F8½j
-¨F*àWø%°»ñ
-ðÀø¹ Fð¬øàF¹ñ
-ð@Fë “ÿ÷ ü›Ùø
-0±ðøÈø
-ë ÿ÷ÑûZø0Ùø
-žØø
-àFÿ÷åÿP±™#
-Ðæ#
-FOôÌqÿ÷𿵠Fÿ÷÷ÿ± FÎ÷»û ½
-Ft!ÿ÷⿵ Fÿ÷øÿ± Fü÷Œÿ ½
-F!ÿ÷Ô¿µ Fÿ÷øÿ± F×÷"ø ½µJhDh”BÑÃh3±›k#±˜G½Oðÿ0½oð
-°½×º
-©"ð÷Vÿ
-ª˜G¹ Fÿ÷§ý
-F Fð÷!þx±4¨ð÷äü
-гõÌ Ð+Ñ€h°]øëðé¿€h°]øëý÷è½€h°]øëþ÷»Oô§s
-ÐÆ#
-Ðé#
-ài- ÐOô€s
-ài@- ÐOô‹s
-ài€- ÐOô–s
-ài - ÐOô¡s
+±h` ±Âh`½pµF
+“`ÐU±¯*F9F$¨/ð¾ø*F9F,¨/ð¹øš$« “š ›ÓBÙx3Û²ø9
+›×÷¦ú
+›3
+“›
+š™D›“BÇÚ™˜Í÷»ú
+ {Dðãø"Úà˜Æ÷ÒþÆ÷¨þ€FÆ÷¥þ‚F¸ñ
+ FDFOðÆ÷©þ˜Æ÷¦þPFÆ÷£þ¸ñ
+™RF˜Ç÷0ù
+ K
+ ðàÿ¸ñ
+ ðµÿ F°½èðÇ÷Sø ð@F + аõ€Ð@ò©#d"
+Æ÷~ý@FÆ÷{ýPFÆ÷xýÇ÷×úF
+
+FF¨ÿ÷ÿ±˜°]øûOðÿ0ùç7µFFš“ÿ÷µýF¹(`°0½©
+ñûÑ‚DBØS
+ñûÑXDƒBˆ¿
+ K{DðÊý F°½
+ {Dð®ý F
+
+ {DðLý F
+
+ {DðÐü F
+
+ ðOü F
+
+x3‚±2F Fù÷,û°p½ Fù÷ñúx
+;JQF@Fù÷úH¹˜#
+K{DžçF|ç
+FF(Fø÷Ôü(Fÿ÷ÁÿFx¹¶#d"
+ñûÑ‚DBØS
+ñûÑXDƒBˆ¿
+hÛ ³ëÒ?ÓŒ¿
+«x"F“ÿ÷vÿ"h9h0hð›¿*hZF(­‘(FOô€a’
+ ðHF$ÿ÷óû3Y2Kø
+0Ph±ðùÉø
+ë #`Ùø
+F!ÿ÷ñ¿µ Fÿ÷øÿ± FÕ÷“ø ½
+Ft!ÿ÷㿵 Fÿ÷øÿ± Fü÷3ÿ ½
+FOôÌqÿ÷Ô¿µ Fÿ÷÷ÿ± FÌ÷´þ ½´JhDh”BÑÃhK±›k;±]øKGOðÿ0]øKpGoð
+°p½ ñ 0F÷÷ û±ø 0#±t#
+¯"9F F÷÷Úû
+K {Dÿ÷ ú Fÿ÷xý¹ç:F1F F¨G
+FˆFF Úø#f"
+гõÌ Ð+Ñ€h°]øëð½€h°]øëý÷V½€h°]øëþ÷¥º@òW"
¹Új
-±^kF¹Oô«s
-Ѐ+ÐOô®s
-K}"{D ài´õ€ Ð@ò“
-KF{DÝç+h(F!hi˜GF ¹ hÿ÷ù%`Óç |½â°
-©"ï÷±ÿ
-¨"yD1ï÷ÿ
-©"ï÷ÿ
-¨"yD1ï÷oþ
-à0Fï÷Ñÿ
-àË#
-±ÃhS¹–#
-Ò~#
-š3Fý÷rÿ±›#` °½èð
-©"ï÷»ü
-¨"yD1ï÷%ü
-©"ï÷ü
-¨"yD1ï÷nû
-Ð1#
-K‚"{Dþ÷æø F
-à@ (`1±F1F°½èp@÷÷9» °p½
-©"ï÷óú
-¨"yD1ï÷]ú
-©"ï÷¤ú
-¨"yD1ï÷ú
-KA"{Dþ÷ ø F à
-KA"{Dý÷´ÿ F à&9F@"€ø@`%ðþý(Fÿ÷Ùþ0F¬`þ½
-Ò@ò_
-à“HFÍø
-Ò@ò?
-àFÌ÷ùè
-™BFÜ;™B€ò‡€Aò™BcÑ[àAò ™B
-Ð+Ð@òß
-û½
-‘!þ÷ÿú½µ
-Ú@òu#
-©"î÷7ý
-¨ "yD1î÷¡ü
-©"î÷ìü
-¨ "yD1î÷Vü
-0ðˆùF
-¿‰h#ÿ÷¿‰h#ÿ÷¿+-éÿGFOð
-0ðªøFH¹ú#
-0
-à`h±Ä÷¦øF9F0F€"ì÷ßø¹
+±\k\¹Oô«s}"
+Ð@+Ѐ+ÐOô®s~"
+¯"9F0Fö÷û
+м#o"
+±Ãh[¹–#
+K {Dþ÷¡ù(FË÷Ýüáç0Fö÷½ù
+ùF
+F™›h 3ðpú
+®"1F8Fõ÷3þ
+¬"!F0Fõ÷Ïý
+KA"{Dý÷ÿ F°p½
+KA"{Dý÷9ÿ(F°ð½$@"9F€ø@@*ð›ü0Fÿ÷Éþµ` Fðç
+Ò·#d"
+úðø `
+ñFñ
+àFÊ÷èû—CFÍø
+ñƒFñ
+‘BÜAò ™B€ò‘€Aò™BlÑ
+ÑiðíйÊ÷ýà`¦`!@à.úÑiðÀñç+ÐOôÓst"
+þ÷Ûú°]øûµ«“
+®"1F(Fõ÷gø
+®"1F Fõ÷ø
+Ðj˜B Ñ#HxD
+0ðúF
+¸ç@F¶ç$K,FªF¨F.F{Dºç!K{D·ç›RF IHF
+ç+-éÿGOð
+0ð4ùF
+0ðqøF€¹#F
-ÑžH_"žIžKxDyD{DðþðþÝø(€¨ ’ëÂ@"@9$ðü Oð
-ë„ê~dëêþ^ëÍø$àŠêñJ
-ëë‡ê±7™êp`™
-ë ˆêûSÝø °ë
-“êøAë‘yŒê¸<‰êqiÝø€ ëŽêñQ‘ID›…êñEé‡ê±71ˆêqcë
-Òª#
-ûú°F ëÊÍøH ë
-Eë Íé«Oð
-Íé« ë ÍøT°'±HFAF:F$ðúÝøT 
-"F+Fÿ÷ÙýÝé#ºDÝé 2Cñ
-ÿ÷ÁýÍé«ë
-êû þ ëŽàÝø4 ë
-ë ë
-[ø
-Kñ
-Kñ
-Kñ
-šF(F
-ÐH7"IKxDyD{DðIùð[ù°p½
-F FÎ÷Nø0³¨©2FÎ÷Øø
-ë
-ØH×"IKxDyD{Dð3øðEø
-àchSø%
-Fµ
-ÿ
-F
-FF±
-ܱ4DEñÑ
-JzDû#ÂhÙhŠBÛ Ü
-±#ðû»FpGOðÿ0pG pG
-±#ðÌ»FpG÷µF
-±#ð·ûãh`h/aë`£h«` ±ÿ÷ºþF¹ àF h±ÿ÷²þ@±ci…èA
-±#ðf»FpG
-±Òh¹I0FyDà›¹ Fÿ÷þFp±ÿ÷ÄÿF ¹8Fÿ÷¹ÿF(±0F*Fÿ÷îýFàhF!iâhì÷ÿhFí÷°ùF¹
-L†°F
-I|D`X
-œ Iè
-L†°F
-I|D`X
-œ Iè
-
-L†°F
-I|D`X
-œ Iè
-L†°F
-I|D`X
-œ Iè
-L†°F
-I|D`X
-œ Iè
-L†°F
-I|D`X
-œ Iè
-“i¹!ð°þFP¹l#
-ú÷dü#h
-(
-(
-(
-™JF
-›ªBø=n±YF0F ›û÷ûFà¹ê#
+ÑŸK_"ŸIŸH{DyDxDð†ýð˜ý
+› ñP
+@"PF”ëÄ@9)ð¡ú#Oð
+›ë‚
+DJø# 3+ôÑ›™ð
+“Ýé4
+øOêJ“KFX
+0€
+3.F“ë
+“Kë “
+Ý@òÕ3€"
+Û@òC"
+š(F ™
+ÐK7"IH{DyDxDðhøðzø éç
+ØKå"IH{DyDxDðNÿð`ÿ!F
+Fµ
+F
+ÿ(F8½Fûç
+F
+F±
+h#SCJzDÑX(ð³ºLŽ
+h!K{Dû3Yh(ð¨º
+ùˆ¹OôÊse"
+±(ðÌùëhhh'aã`«h£`رÿ÷³þFÀ¹
+±ÒhJ¹I:FyD0Fÿ÷÷ýF F°ð½s¹ Fÿ÷‚þFH±ÿ÷¿ÿ¹(Fÿ÷µÿ±:FFèçâh!ilF Fó÷—ú Fó÷—ýF(¹
+FF/HxDÿ÷^ýF¹
+M &}DûTghBѧh—Bѱ#h` à3+ïÑ
+
+
+
+
+
+L M|DdY”œ” œ” œè
+L M|DdY”œ” œ” œè
+L
+M|DdY”œ” œ” œè
+L M|DdY”œ” œ” œè
+L
+M|DdY”œ” œ” œè
+L M|DdY”œ” œ” œè
+“ѹ&ðhûF¸¹l#F
+«˜
+˜±þ÷Ãý(F°½èðyK&FWøOð
+™
+› © “ ›¸ñ
+F@F1Fû÷¹ùF
+(”¿
›cb ›#b
-“˜±þ÷"þ ˜±þ÷þ
-˜±þ÷þ
-“çch¹£h ¹cj3³(F!F!ðeþ³à!F(F!ð¯ý ðú4
-˜³þ÷éýà&
-È÷Ìøÿ÷HøFP¹Oôªs
-!ø0
-)8µFÐ)Ð)ÑL|DàL|DàL|DàL|DI(FOô€byDë÷ù!F(FOô€bë÷þø I(FOô€byD½è8@ë÷õ¸
-#
-+øÐsI "yD"ðêøF@±OôÕs
-,
-Fà¢ñA)Ø7:à¢ña)ØW: àOôös
-ÜOô
-! ñ øø`ÿ÷ü9FBFKF>¨ÿ÷Cü¨Ç÷”øÍø
-HF!Fþ"è÷eÿ
-# "Cp
-
-*&Ðë
-0F
-ñ ê÷?ûF8¹@ò—#
-½çOð
-(FÍø ê÷ûF8¹@ò¥#
-Sp
-YF F "ø
-€!ð‹ü
-Dø
-€šRD’ºÐ
-#Cp
-`™rh
-`™jh
-``š`ý÷fþ0Fý÷cþ(Fý÷`þ à8Fê÷êù0Fê÷çù(Fê÷äù
-Å
-®˜
-›š`¹ñ
-›“Oðÿ3ÿ÷Âÿ°
-œF
-œF
-›“Oðÿ3ÿ÷ÿ°
-œF
-›“Oðÿ3ÿ÷çþ°
-›“Oðÿ3ÿ÷×þ°
-œF
-1FBF;F
-©"ê÷íû
-¨ "yDê÷´úF0¹%KC"
-à Fð»ÿðïù Fðñþ°BõÑ¿ç
-°½èð¸
-I¨ "yD 1é÷Åÿ
-ÐHm"IKxDyD{Dðýð.ý(F!Fð=þ ¹ F ð"ù
-à(Fð)þ ð ù(Fð_ý¸BõÑŠç
-°½èð}µ
-FIyDÿ÷¾
-FIyDÿ÷¾
-©0"é÷“þ
-¨©"é÷‹þ
-¨©0"é÷zþ
-ñ  "é÷×ý
-à FÆ÷yø
-´
-©¨é÷ûÿF8¹@ò
-g@FÅ÷aÿ
-Д#
-ñÿ0@PEÓë<DEÒŽ#
-Ó•#
-àHFAF ð¿øs\
-ø 0 ñ ÙEôÑ‘à ñ h™HF
- ñ HFQFZFÆ÷Œþ
-©BFð7ÿg›CDg“f›³ëf“>ÐÝøOð
-
-à@FIF ðUøø :«ø ñ¨EòÑ8F)F ðHø ¹"FàHË"IKxDyD{Dðöøðùk!à:¨øà\pD ÑT
-;«BôÓR»BíÓoç
-Ÿ ž 4±Íø À°½èð@ÿ÷—¾j#
-­#è
-°½èð‡ô«
-à@òq
-©"é÷ãû
-¨é÷súF
-¨é÷qúè`
-¨€!
-¨è÷ÿ‘à
-¨R™ø÷Wü
-¨©ªè÷âÿ
-¨©0"é÷»ø
-ñšø é÷ø
-© "é÷5ú
-¨ ©0"é÷ ú@¹Oô×s
-¨©"é÷¬ùFP¹Oôãs
-©"é÷ù
-¨ñ(
-"è÷Ñÿ
-ðŽÿFP¹@òi
-ð¯ÿ
-© FAø=ÿ÷‰ÿF(±›˜Â›“B Ð Fÿ÷‘ÿ‹#
-ð¸ýÚ
-¨€!–è÷úú¹
-¨è÷+û2à›
-¨©ªè÷ïû
-ðQýF(±›šÒ ›“B ÐÚ#
-KD"{D÷÷zú F
-ðOý
-ªHFè÷LùFP¹Oôñs
-š àHFè÷ÏýFHFè÷Íý9FF¨è÷·ý
-ðÌü Fð†ù°BõØ
-ð%ü à
- ëši*ð|JŠê
-ë™h)ð|I‰ê
-
-Íø °Íø
-Ýø ê
- Ýø  ‹ê
-êÝø
-±ð~»FpG pGF@h™hú÷v¾8µ ú÷(þF ±
-IxDyDú÷|ýF ` ¹ F,Fú÷&þà 
-Kh"{Dö÷û F
-F¨Fç÷€þ¨ÿ÷°ÿFh¹x#
-à FÎ÷øFX¹Á#
-F¨Fç÷€ý¨ÿ÷rÿFh¹Ñ#
-›Ä÷@þF˜ú÷Mù
-" G
- °p½
-ð
-¿™Oð
-C¡x4Bê"’à!xbx4Bê"’ àø+’à F™ªð²þ
-whÐ8Fâ÷ÇøƒFðèüFYF FJF¨G¹Oðÿ8—àNI F"yD¨G
-Ñ(F!F²h3hÿ÷iþ
-I F"yD¨G¹fç
-’"F.Ÿÿ÷ÿý
-˜ “Oð
-˜YÉëà
-˜IFð(þš‚FSЃh0FšBÑ™BF¨G
-#F
-àš²õ
-ÕËë(FF1F“ÿ÷&ý›³ä0F ™ š¨Gà± ››D\Dºñ
-F“é±Kh+ØIyDË“ù‘0YÐ
-ÐV#
-Ð}#
-Fà#
-"ðEùœ$±#x±»œB Ø
-ÑàP+ÐU+Ñ
-Ð@ò¥#
-©(Fð¥ýF8¹@ò3
-š˜`ƒèD
-àrI *FyDõ÷{ø F
-mJmI{DzDyD`‘Óø
-ñ 
-`ÒÑäçô€0Ñ«`,a
-à@ò
-"ðºü›F#±x±¾³B Ñ
-ðü F©ÿ÷Úÿ°½7µF Fõ÷•ùt(аõÌÐ(Ñ h)F°½è0@þ÷¼ h)F°½è0@ó÷ƾ h)F°½è0@ó÷‡ºP#
-àâ÷Èþ `
-ÐRHö"RISKxDyD{Dð™üð«ü F©ÿ÷ñþF8¹ý#
-àI F$yDã÷ÕûàIyDã÷Ðû
-F˜hðÄúDIF;F2F FyDä÷êú8Fø÷û@I2F FyDä÷áú+h FÙh
-K"%F{Dô÷Ûù à1F
- Oð
-Üð#
-"yDã÷Dú
-K"%F{Dó÷©ÿ à1F
-I(FyDã÷vÿ à Fø÷ø
-+Ð +ШƒøPŒà¨øP<2O*Ý0FiFâ÷Wÿ
-”Oêà •ëCŽD®õ~ñÿ3 +~Ø“y /TzOêÃëCÑy Dz£õsOêÁ
+“˜±þ÷7ý ˜±þ÷3ý
+˜±þ÷/ý
+“ç6I0FyD'ðµøF°¹£h
+(”¿
+(”¿
+!0F3p
+I FyD&ð?ÿ¹½è@Æ÷¡¹
+)8µFÐ)Ð)ÐL|DIOô€b(FyDñ÷dú!FOô€b(Fñ÷^ú
+I(FOô€b½è8@yDñ÷UºL|DæçL|DãçL|DàçB¿
+"ëEø
++õÐ[I "(FyD&ðÌýFX±@ò­m"
+,uÐ
+‰FFPFF“ï÷îøHF&ð ýNIF " FyDï÷Œû (YÑ:FIF Fï÷…û¸BRÑGI" FyDï÷}û(JÑ0F&ðñüF
+!(F…ø
+RF!FHF ®
+·
+#Cp
+PF&ðNú€F0"™8D&ð.úF
+ FÇø
+"Zp‡
+(F
+ñ ð÷}üF(¹@ò¡#
+ °çOð ´çchƒø
+"Zp
+Úø
+ÝÃ] +Øñÿ0ùÒD
+#{p
+;hRFHFDî÷Iþ
+`™jh
+`™bh
+`bš`ý÷<ý(Fý÷9ý Fý÷6ý Y°½èð
+›Ëø
+ð§þFHF ðù®çÿ÷ÿ÷çF0Fºñ
+ðDÿF FÒ÷¸ùŸçÿ÷cÿ÷çxê
+œ“F” œ”œ”
+œ” œ”œè
+œ” œ”œè
+œ“
+œ” œ”œè
+œ“
+œ“F” œ”œ”
+œ” œ”œè
+¯[F
+Üo#
+›
+ü°0½Àã
+¯Oð B9F Fð÷:þ
+ýF(±F(F$ð[ü
+à!F(F$ð¶ú
+à!F(F$ð„ú
+ð‰ýÚ
+ðyý
+ðÈüF
+ÐKj"IH{DyDxDð§úð¹ú9F0F$ð°ú
+ð¾ü—ç0F$ðªú
+ð¸ü0F$ðŠùEõÑ’ç
+FIyDÿ÷¾
+FIyDÿ÷ý½
+K{Dæçbh±!h$ð/ÿbhäç±!h$ð)ÿ+hbhD+`ô絡
+¬ˆF‘F!FœJ(˜“ð÷ù(¹Û#
+"QF0Fð÷Öø
+®F0F›F’ˆFÄ÷èü« ñ
+“
+i›šE*Ó ñ$ Ùø
+½B)Ñ)F@F$ðtûq»!F ˜E£Ù{ ŸB1Ø9Döç
+ñ
+¶ç8FIF$ðJûø0ø 07ÉçKÕ"IH{DyDxDðÄüðÖüÊ\ø ÀbDDÊT
+;Âç
+­˜GciF˜GF0FÃ÷‡û#"©8F”•Íø€
+­")F Fï÷ü
+üF
+ª ™(F
+› ª ™(FDÂ÷˜ÿF
+8FDî÷KÿF
+¯IJ9F Fî÷ÿ
+"QF8Fî÷
+ÿ
+"QFXFî÷ïþ
+­J)F Fî÷µþ
+¯Oð B9F Fî÷Qþ
+" ñ(8Fî÷±ý
+ðßù¯Û­8F)Fî÷¨ý
+ðÒù
+K¿"
+I H{D*3yDxDðç h0
+FF(Fî÷¦ý(Fÿ÷±ÿFx¹x#d"
+K{D£ç FÌ÷ýúF
+FF(Fî÷ ü(Fÿ÷qÿFx¹Ñ#d"
+›Ã÷­ûF˜ú÷Ëü F°ð½Fúç
+DDEòÐø;QF0F ðû\º\ø0ø "ÈG
+")F˜ G
+ °0½ÿ(Ù.J­F !(FzDú÷cü")F˜ G
+±#p" ñ˜ G
+¿›
+ŸÛ²“›™EÛ›œB¸Ñ(F°½èð"x4øBê"Rº’²Ñç"x4 ’Îçš1F F ðßÿ
+šÉ²
+ð“ «“ø0 “¹çDFôç
+(Fú÷%û›‚F³õÀ6гõ€Ð
+.š9F
+›0FJêÿ÷Oþ
+#F¢ç›³õ
+Åç
+FFHxDÿ÷¿þ°p½
+FFHxDÿ÷žþFòçOðÿ4ïç
+h¨‰hç÷ºú
+þëç­(FÂ÷*ý:FQF(F
+ùF
+ñ
+0F!ðÏûƒEdÓ- ñ4 IF8FwÑê÷*û
+hÊø
+©2F
+"©!ðMÿ›
+ÚOôÓs‘"
+§ë
-ëA
-‘z¢DÔzªõzOêÁ ëA ¡D©õy(Ý{/,%Ù9,#ØQ{/) Ù9)Ø$²/OêÄëD D¥õuБ{.)Ññ&¾B¦ñÚøÀ¼ñ/ Ù¼ñ9ññÙà
-d!” œÍø
-“ “ “ “ÿ÷'þ
-¨©ªÿ÷þ
-›+6Ü
-Oð
- ¿Oð
- Oð
-ëF‘FhÕ¨ÔàÐI "yDâ÷ºý
-"yDâ÷°ý
-#ÍøÀã÷ëü
-]ÑàiI FZFyDã÷tü
-Fð&ûF
-
-û‡BâÓEI FyDâ÷LûàCICKyD{Dã÷»úkh
-à›h
-Ñ+hô€?¿
-FØh
-ر=<,Ñœ E ¿<$=$
-Ðh[hhö÷:ÿªF Fÿ÷Œý
-hhh#hÑ+Ð+ Ñà`hQh½è@ÿ÷(¾`hQh½è@ÿ÷¾½)ðµÍ°FF‘Ð)0Ñà2«’“«2“à«’“«“­0F©*Fð…ýè±Ô±•#©#`Fí à)F0Fð‡ü9F¨ÿ÷¹ÿ@¹#h53#`0Fðhü…BìÛ˜àOðÿ0M°ð½µF€±h+Ñ@hðšÿà+Ñ@hðüÿ F½è@ö÷´¼½8µF ö÷üFp±
-à6HFðþ› hžBßÛ0ü÷ýø(F°½èð‡
-¨¿
-@hðúGh8Fðìü F9FðÁúFp¹(h0ü÷¬ø8Fð¡ý K FLFXøð$úà6ÿç›(hžBÛÛ0ü÷˜ø F°½èð‡˜†
-F‘©Fð×ú¹
-‘ ‘‘ à˜øÀ¼ñ
-šC!C
-  ‘à! ‘
-‘ ‘‘
-3#
-K€"{Dñ÷”ý
-hhhÀpGpµFÌm ¹ p½chc¹#hÛ¹øç)F`hð0ýõ÷`ÿ°BÐ5
-Ð5
-Ѫ#
-›#a ›casÐ (àN~D3hs¹HxDð¾ûF0`8¹ä#
-T
-à0F!Fð»ùCh
-ðü`±#iÛhð Ð f!Fff
-ðÓû jÀó@0½sµF†o
-à`f!F&f
--Ü
-"
-6ðôü
-= ñ à -ïÝ-íÜ1F¨ " 6ðæü =«2xZ*Ð-*Ð+*Ñ0",FpZpš3Fà-ÕÐp¬rxZpññбx.)Ñì6=àx609 )Ø<3F¬BÐ3F
-¬hFYC”’
-Ñ ¹
-à;hi`¹&àúÝ
-jÑÕðàð@ðÄ€*j
-‘”š2’˜ð€ü›ƒBÿôU®
-š `›™ `›`ðPÿ ™h ±ð ø š
-“ ® “ý÷Ûüco„F
-© “ ªãhÍøÀ“«ÿ÷nýÝøÀعaF#l F˜G„F¹
-››¹ÍøÀ
-©«
-žF±›– ž£f›#g ›cgà#
-#
-àYFPFðïø™Fý÷ú0± ñ PFðÓøƒEïÓPFðÎøƒEÒHFðŠüàOð
+F{7Ñ0F!ð®þFßø¤‘Oð1 hJùDzDÉø
+`ÎÑàçô€1Ñ£`%a
+"!ðåý›F#±x±4D£BïÑ
+Ú@òA3‘"
+ð:ü!F(Fôç
+þ
+ÐPKö"PIQH{DyDxDðþð¡þ©`hÿ÷íþFH¹ý#
+p
+ 'cç–I" FyDé÷Fÿ
+" FyDé÷1ÿ
+úð'ÐÙø
+&4ûS` h;` `p½
+Ж¹I FyDé÷Tý
++Ð + ÐøPŒ2O*àÝIF0Fé÷Õü
+y
+$Ky0:û21: *
+à£ñ0Ëy¬ñ0 ®ñ0£ñ0û3Mz¥ñ0û \Íz¥ñ0û^[Ý {¥ñ0ý² -UØM{0=_ú…ù¹ñ NظñûUMÐŒ{.,JÑoð ññ «ë ©ë
+ ë ÐEÝø«ªñ0
+ºñ òÙßø„€Z.øDXø" 1ÐN~D–‘ø€x¨ñ0 Oðdû ø0>Oôzy ûˆŽxÉxOð
+ —0>” û†•Íé
+3Íé 3ÿ÷-þ
+¨ÿ÷#þ
+›+7Ü
+ùÈJCÈI
+0ÑvI!" FyDé÷’ú
+ #ëæWI " FyDé÷Gú
+" FyDé÷;ú
+#:#ê÷žù
+9FRF@Fé÷!ùPE Ñ#x·»±"IF@Fé÷ù(Ð@ò#
+K
+Ñ+hô€? ¿<
+kR¹ÚjÈjÑ*±˜j‰j½è8@ð‹½8½8µFÃh FS±ChC¹ëh{¹
+hhÑhØhÿ÷ÿ
+hhQiXiÿ÷½¿
+hh‘h˜hÿ÷·¿0µ
+ÜØø
+à)F0ið«ûKFRFAFÿ÷Ìþˆ¹50iðû¨BïÜd±#h8F;`ch{`ÿ÷—ÿ °½èð‡LFòç Føç@hpG-éðG†°ßøÌ€FFðoûøDFð± h ñ 0ü÷üø hKF2F!@hÿ÷þ(Ú h¯0ü÷ðø;F2F! Fÿ÷ÿ8¹(Fðxû
++Ú(h0ü÷qøáçë
+@hðèúGh8FðÐý9F Fðæûx¹(h0ü÷^ø8Fðñý K FXø0F“ðñúÆç6›(h³BÜÜ0ü÷Jø¾ç
+"Íé"ZEÛÝé!
+C
+™
+C Ð"Íé
+"Íé"
+ñDND¶õ€$Ý™#
+ ø
+ 3š
+K{Dïç+Ñ#h"
+±Ch`pGChhö÷‡º
+FF@òŽ0ÿ÷Aÿ(Ñ"F)F F½èp@oçFÿ÷ÊÿCÑK2F)F F{Dh½èp@Gÿ÷¥ÿ2F)Fƒhöç p½
+›+a ›kaÐ$ÉçN~D3h›¹HxDðUüF0``¹å#
+M&}D5ûP4ÿ÷¹þ,øÑLI|DyD hðhü
+h€h‰hã÷`ý
+ð­ûh±#iÛhð
+Ð f!Fff
+F
+FsµF+Ð+Ð
+#ef#f!Fãi
ñ
-SÕÛø PÑ ñ Oð
-ñ àQF(hð ÿƒFðŠýÍø
-ðcý
+ç–B‘Ý&"!F"f
+¹E ѹñ
+’hÍø°Íø°“CnÍø°“«“«“ ˜ð¬ú›ƒB7Ó
+›h ±ð¶ý
ñ
-ÂEçѺñ
-ðbý
-ðný
-Ü@òês
-¹A³ F(FðÁýBÑ@ö­
-Fÿ÷ª¿
-F
-Ý%à f!Fãi
-Ð.¹¢i2Ñà"
-°½èð¨ë
-Úà!F(Fð ÿƒh4;ƒ`DEõÛ8F½èð-é÷C‰FF˜FF¹
-Ðh£¿|`Ñ0F)Fðýx`ÿç þ½-éðAˆFFFF±h$¹ð]ûF
-àCh¹Ü÷ÿ``ch
-±[h`½pµ FFF¼÷ìÿð F ¿%Oðÿ5¼÷áÿò÷[ÿ*FF
-FIµF{DXX!F½è@Ø÷ܾ¾H
-FIµF{DXX!F½è@Ù÷H
-FIµF{DXX!F½è@Ø÷ž¾~H
-FIµF{DXX!F½è@Ù÷œ¹^H
-FIµF{DXX!F½è@Ø÷œ¾>H
-FIµF{DXX!F½è@Ù÷®¹H
-FIµF{DXX!F½è@Ø÷^¾þG
-FIµF{DXX!F½è@Ù÷\¹ÞG
-FIµF{DXX!F½è@Ø÷\¾¾G
-FIµF{DXX!F½è@Ù÷n¹žG
-FIµF{DXX!F½è@Ø÷¾~G
-FIµF{DXX!F½è@Ù÷¹^G
-FIµF{DXX!F½è@Ù÷Ò¸G
-FIµF{DXX!F½è@Ù÷š¸¦F
-FIµF{DXX!F½è@Ù÷Š¸†F
-FIµF{DXX!F½è@Ù÷.¸>F
-FIµF{DXX!F½è@Ø÷ö¿ÎE
-FIµF{DXX!F½è@Ø÷æ¿®E
-FIµF{DXX!F½è@Ø÷ú¿fE
-FIµF{DXX!F½è@Ø÷Ö¿E
-FIµF{DXX!F½è@Ø÷z¿ÖD
-FIµF{DXX!F½è@Ø÷V¿ŽD
-FIµF{DXX!F½è@Ø÷j¿FD
-FIµF{DXX!F½è@Ø÷F¿þC
-FIµF{DXX!F½è@Ø÷꾶C
-FIµF{DXX!F½è@Ø÷ƾnC
-FIµF{DXX!F½è@Ø÷€¾rB
-FIµF{DXX!F½è@Ø÷$¾*B
-B
-FIµF{DXX!F½è@Ø÷8¾âA
-FIµF{DXX!F½è@Ø÷¾
-FIµF{DXX!F½è@Ø÷ð½RA
-A
-FIµF{DXX!F½è@Ø÷€½â@
-FIµF{DXX!F½è@Ø÷]½
-FIµF{DXX!F½è@Ø÷8½R@
-ÝHEÐZ(ÐŒ(Ð#iCô
-ÿ€F8¹›Z Ð#iCð€#a+àØ÷tù(a@FÛ÷‡þ
-³
-Oðÿ2’ÑF­à(hQFð»úšFƒh“BÐðŸúF
+Ùø
+æç›/FÍø°“fæ)F ˜ðÓøƒjF
+›`›³õà´¿
+.F½BíÜåe)F mOð
+“ ñ0 Íé 3ý÷…øcoFšYF F “ãh“ «“
+›#g ›cg™ F#káf˜GƒF
+hh‘h˜hý÷øFP±@ò¡sr"
+
+K{D4ç
+FFÿ÷¨¿
+Hñ|*F!FxDó÷¯û"
+hhhhð͹µFH±ÿ÷³ÿ jó÷5þ F½è@ó÷0¾½øµFFFF
+FF
+FF!
+Ž
+ù0½ üç
+°½èð
+L
+àFìç B!Ü,³a0FðØÿ…h5@Fððý€F
+K{DÚç©8FAø]ð§ÿ2F)F Fä÷ø(Fó÷‚øßçc"
+K
+FF“F°ß÷•¹RC
+FF“F°ß÷Ò¼2C
+FF“F°ß÷X¹C
+FF“F°ß÷€¼òB
+FF“F°ß÷U¹ÒB
+FF“F°ß÷’¼²B
+FF“F°ß÷¹’B
+FF“F°ß÷@¼rB
+FF“F°ß÷¹RB
+FF“F°ß÷R¼2B
+FF“F°ß÷ظB
+FF“F°ß÷
+FF“F°ß÷²»¦A
+FF“F°ß÷v».A
+FF“F°ß÷f»A
+FF“F°ß÷»Â@
+FF“F°ß÷̺J@
+FF“F°ß÷¼º*@
+@
+FF“F°ß÷κÞ?
+FF“F°ß÷¨º’?
+FF“F°ß÷JºF?
+FF“F°ß÷$ºú>
+FF“F°ß÷6º®>
+FF“F°ß÷ºb>
+FF“F°ß÷²¹>
+FF“F°ß÷Œ¹Ê=
+FF“F°ß÷<¹º<
+FF“F°ß÷Þ¸n<
+FF“F°ß÷ð¸"<
+FF“F°ß÷͸
+FF“F°ß÷¦¸Ž;
+FF“F°ß÷2¸;
+FF“F°ß÷¸
+FF“F°Þ÷è¿‚:
+FF“F°Þ÷¬¿
+:
+hhhhà÷s»µ
+øƒFX¹›ZÛÑ+a àðþ d
+þ(³›3“#hXiðký™BáÓÜ玹#hÓø 
+
+Õø›œB Ü»hí=`Âç<Öç<àç
+ 
+I
+
+
+
+
+
+
+©0FAø=ÿ÷­ÿF(±˜›šDšB Ðp#}"
+ÿF˜ÿ÷ÿîç h÷µF©F
+ý,`ëçsµFFh±í÷ŒûF`¹û#,F
+KA" {Dí÷,ø F°p½!Fí÷¹ü1F(Fÿ÷«ÿF(Fí÷ûðç
+KA" {Dì÷æÿ F°p½!Fí÷ü1F(Fÿ÷eÿF(Fí÷Jûðç
+KA" {Dì÷ ÿ F°p½!Fí÷Jü1F(Fÿ÷ÿF(Fí÷ûðç
+K°"
+I H{D3yDxDðç(Fõ÷èþ%f´çh
+hhQhXhð÷Ì¿7µF M}Dˆ±
+Ó3KHFOð Zø0F“ðƒúÃç™HFð]úš
+K hëXF“ðûùKàhëXF“ðôù F°½è0@ð÷…¼¸
+Oð
+`T¿ñOð
+±ð›ýg`@òê 'hð÷Éü
+ñÿ:‘h
+ñ
+
+K{D¼çAú
+2F0!8Fü÷ûÔÛ1F8Fü÷ûFü÷*ýÝ÷ÌÿF¹ñ
+h*
+Ñéxkx*x‘©x
+‘F˜F ž]¹Oôás‰"
+àFAòPFðrÿ
+FF Fÿ÷{ÿ°½-éðO…°HO FFDð1øF
ñ
-(hðüù‚EÿôL¯8F
-©(FAø=ÿ÷µÿF(±›˜Â›“B Ðp#
-°p½†
-à)Fí÷êú F1Fÿ÷°ÿF Fí÷¢ù(F|½Š
-à)Fí÷šú F1Fÿ÷nÿF Fí÷`ù(F|½
-à)Fí÷Jú F1Fÿ÷,ÿF Fí÷ù(F|½‚
-©
-©
-FXiú÷Øü a%àñd
-àkh¹ÿ÷¥ÿh`hh¸±!Fðù˜±¹n¹à»h¹ðEø¸`¸hH±AFðù
-Fðû Fÿ÷©ü›
-Ô»ñ ÑAh
+HFðöÿ‚EçÓHFðø6@Fðíÿ†BÃÒ1F@Fðùÿ™F@hðéû»Ùø
+Ãç)FJF˜ÿ÷oÿF
+
+K:h{Dê÷µþ F,FÝ÷ìù¤ç
+Ó!h
+šØø
+“›3“HFðþ›ƒBÿô6­KHFZø0F“ð:þå
+““:K{D“èçý
+I2F[F FyDà÷ø2F¹h Fÿ÷…þ5Ñç
+Ø
+þ°ñ
+OÜ
+ÑYF0FðuÿP¹!(Fðýú
+K*h{Dé÷ùÁç
+×
+h“B Ñ+Øßèð  
+K {Dè÷ñþN¹
+K)F{Dhð!þF ¹Y#
+œˆF’F™Fð-+ÐOðÿ2
+h-éøCF F:*
+Ý/ à
+Ó/?Ð
+ÑCh±1 ½èðƒh
+4Ùø0”“ÿ÷²ÿ#F
+K {Dè÷òù
+®F‰F””úDFøMðöø€F@FðWþ„B Ó™
+I " FyDÝ÷mùih Fó÷ü 8½
+h‰hÝ÷$¼D± K*F I{DyDÝ÷Öÿ Fp½K*FI{DyDÝ÷ÍÿÜçFóç]Ÿ
+±FàçƒÕKjðˆÐÕÊjÂóÀFpGFûç"ùçjCÕ‹jðÐ
+±FÅçÕËj[Õƒ ÕKjð¨¿"
+±Fcç pG pGµFx±ƒhÚ Õ›Õ
+±FHç j›F¿HjÀó@
+K&
+M I{Dh}DyDðÀÿûP4ÿ÷“þ ,øÑK
+
+¯ çOðÿ3ãaç
+àHEÐPEæÑ£jCô€sà£jCð£bÝç£jCðùç£jCðõç£jCð ñç£jCð@íç£jCð€éçAFàkðýChFk³h
+ü„BÓ °½èð!Fhhðüh€F
+à!Fhhð¬û9FF
+K {Dæ÷ýû Fÿ÷fÿ(Fÿ÷ÿ
+ $à7NOð
+0$~D
+
+baUSp#i3òçø+¢ñ0÷² /Ø3Cìç¢ñA.Ø7:Cåç¢ña.¿ØW:÷çpµÕ hðh”BÙøk¹p½ ±..ûÐ<ôç¿` `õç7µF¨F*F@øF›¨ÿ÷Ýÿ
+CÑÐ$ðF3‰ç"çç"ð A9)Ù¢ñ0 )Øá Õê*Ù"™“ê÷Kû›¹Dð$ðáç.*Ñð«Ñ7$Ùç-*¦Ñâ¤ÔDðÒçºñØ
+IyDÝ÷/ù2Fa(FÝ÷BùëçIyDÝ÷%ù2F!FôçFåç ¨
+xxñ ()Ø+ú
+K|DF(FãXF“ðhûK8FãXF“ðaû0F°ð½±
+°½èðœcÑ-õÑ"9F0Fð½ø ïç-ìÐ ›+éÜÑ
+F”Fø;S±:+Ððý,+õÑœø0
+¿Oðÿ3
+*ÖÑKjÑø ÀÑø€“ j·î[“Ëi“Ki“ i“‹h“Ñé
+œ£û#èû#äû #Oê
+Kê{åû #‘[A‘ “¬û#™œäû#–Cë›åûg³
+“Gë “Ýé
+4èû4Íé
+4¡û#™œáû#™äû#‘Cë›\
+’Kë šÝéEOêšIêyOêšîûEšë
+Ië ” šmAë
+Ië Oê›e”Dê‹ëœ’Ië š¢ûE
+šîûE$mA¤ šEë
+
+šOêEêuë Jëë šBë
+šë OêYkEë
+
+UEêÉb
+’Jë š¢û EšâûE
+šë OêEë
+ëOêDêtJë
+ë Oê’kJëšIKê‰vAmOêŽDëOê™dë DëœOê[jJêÆ¢ûEšáû EâûEš!Fœ OêEë AêqdIë’A¤Gëë
+’OêVgšžGë®ûEšìûEšæûEš&EëEêu²EëÒEëÛmAÓšEë–ŠFêOêN›Bë“š›£û#ìû #èû#áû#—Cë › › š ™• šFêvOêRA[Fë[ ™žAë™ûOêTgIëMEêÄœ[Bë “š›£û#äû #œæû#èû#ë Cë
+››ÜGêwOê›Cë›GëÒ›Cë ›ëOê‘iJëœDêš“Fë ¬ûgšâûgš±žGë ¢ûgšèûgšOꚉÝéVIë ŸIJêzOêçûVIë 7FžRJë
+·žvAÒJë
+Š™Ië
+
+¬û‰NYFêÃ’J뙞—"ð|BGêƒb
+›#ð|CëZcƒ`›#ð|Ca›#ð~CCa ›#ð|E›…a#ð~D,ð~CÄaCbPø"0î:ðÃñ¸îgkúóî:¸îÇ{'î{´îGkñîúÔ
+K@ò£B
+I
+H{DyDxDmå2
+*ÜÑ°½èð
+*ØÑ°½èð
+,ÕÑ
+,ØÑ jÒøÀÑø$°“ËiÒøà·î[“‹i“Ki“ i“Ëh“‹h“Kh “ h
+“Sj “j “Ói ““i“Óh““h“Sh™ œ“hš“›ž£û#áû #™ëû#™äû# ™ œäû#‘šC뛣û#åû#æû# žæû#‰šDë‘“›£û‰› šãû ‰›âû‰›šãû‰›æû‰›âû‰ š›âû‰ëû‰› š ™Ÿ£ûE› š8FŸãû E›âûE›ëûE›"Eë£ûE›™áûE› ™ãûE›Eë£ûE›™áûE› ™áûE› ™ãû E›áûE ›™ëûEÍéE¬û EáûE› ™áûE#œEë ¤ûEçû
+œäûœë
+Aë$mAë
+˜œ ûE˜F ˜àûEë
+Oê Eë
+@ë ˜ëIë ë
+Dë½OêhHê‡ë
+˜F˜àûEëOêEë DêtëIë’vAë!šDëOêRjzJêÇë
+
+Bë š¢û
+˜&Eë ûE˜F˜àûE˜F˜àûE™˜6OêEëöDêtAëvDëÛIAö›GëOêShSHêšëC뛜£û#äû
+˜œìû
+™àûE˜›EëÉ›Cë›EêuÉ›FëÜ›[A OêYdCëSDêÂ
+Cë›’œ£û#äû
+˜ œäû
+š ˜àûgš˜àûgšÍég˜Ÿ†šB뚘Eêu²Gë˜@ë
+› ˜àûg›ëûg«%ë Oê\fGëFêÃ[¦ûgûw ›#ð|Cð!›OêeGñ
+ëScE`(ð|Fƒ`›b
+*ÚÑ#°½èð—
+­F8F F&ÿ÷Éø9F(Fÿ÷Åø)F(Fÿ÷Áø!F*F(F¬ÿ÷!ü*F9F8Fÿ÷ü9F Fÿ÷²ø"F)F(Fÿ÷ü)F Fÿ÷©ø!F Fÿ÷¥ø>ùÑ*F!F(F &ÿ÷ü)F Fÿ÷™ø!F Fÿ÷•ø>ùÑ*F!F F®Oðÿ÷ñû!F0Fÿ÷‡ø1F0Fÿ÷ƒø¸ñøÑ"F1F FOð ÿ÷ßû!F Fÿ÷uø!F Fÿ÷qø¸ñøÑ*F!F(FOð1ÿ÷Íû)F Fÿ÷cø!F Fÿ÷_ø¸ñøÑ*F!F FOðcÿ÷»û!F0Fÿ÷Qø1F0Fÿ÷Mø¸ñøÑ1F"F F1&ÿ÷ªû!F Fÿ÷@ø!F Fÿ÷<ø>ùÑ!F*F(F$ÿ÷šû)F(Fÿ÷0ø)F(Fÿ÷,ø<ùÑ:F)FHFÿ÷‹û)°½èðƒ·î[-éðO
+,ØÑ
+,ÛÑKj iÍh
+ h§ë ñ€gñ
+*ÛÑ °½èð
+,ØÑ
+,ÛÑKj iÍh
+*ÛÑ °½èð
+*ØÑÑø$ÀÑø àÌiiNiiÑø €‘è"K°î [[` KšžB`JFaÄa¢ë ×U`¢ë£ëÁ`!b
+*ÛѽèøƒÚÿÿþÿÿþÿÿ¬Š
+*ØÑÑø
+KhŠhÌhOië˜cŽiÍi(ð|HëSb#ð~C·î[ë’n i"ð|Bë^l jIjëœgëWf'ð~GGaë–e&ð|F†aëUd%ð~EÅaë”a$ð|DbOêQi!ð~AAb!
+û ˆë˜c(ð|HÀø
+K@òª2 I
+H{D?3yDxDˆç2
+*Ûѽèð‡Œ‰
+
+F!FèFÿ÷áý*F!FPF
+¬ÿ÷åü2F9F Fñx ÿ÷føñ(QF@Fÿ÷`øñP®ñx0Fÿ÷XøñPHFFÿ÷ÀýBF!F8Fÿ÷ÅüBF!FPFÿ÷¶ýIF Fÿ÷ÿ2F!FñP
+¬F
+ñ( HF­®þ÷ÂüYF Fþ÷¾ü
+ñP(Fþ÷¹ü*F)F0Fñ(ÿ÷†ý1F(Fÿ÷äþZFQF@FñP
+ÿ÷{ýAF0Fþ÷£üJF!F@Fÿ÷rýJF!FPFÿ÷wüAF Fÿ÷Ëþ"F1F8Fÿ÷nüQF Fÿ÷Âþ"F)Fñx
+*ØÑ h
+iNiñ|IKh ñ ñ|Bi2ñ~H‹hññ~F¨ëÙxÌiñ|NËhñ6®ëØ~ñ|Eñ~Lj ñ 5¬ëÞ|ñ~DKj4¢ëÜrñ|G7¦ëÒvñ~J
ñ
- àF
-9à)F8Fü÷–ûFü÷¯ý×÷ÇüF¹ñ
-h*
-à!F0Fð+ú*FF8F4ÿ÷>ÿF0Fðú„BïÓ¹½èø@ðº(Fø½ h÷µF F+aØßèð *X
-Ñ©x*xkx
-àIyD±çIyDÛ÷aù FihÖ÷Zý þ½
-’F™FU¹Oôás
-àQFðŒÿF Fð8øFH¹Oôšs
+¥ëÖu)ð|C(ð~H¤ëÕt.ð|N,ð~L§ëÔw"ð|B&ð~Fªë×z%ð|E$ð~DOêêq'ð|G!ð|I!ð~K)ð ØDKD!ð|A#ð|Ië“cŽD#ð~HëScÜDÍé˜#ð|N ë“c
+D#ð~LëSc^DÍéì#ð|Bë“c D#ð~FëSc\DÍé&#ð|Eë“cDëSg#ð~D*ð~CÍéT[D'ð|Aë—cOð
+¯#ð~C“Íé
+Wø*0
+ð Ëñ 3ú ó Ð;K@òÞ":I;H{DH3yDxDJç
ñ
-HFðeÿ‚EHFäÓð‰ÿ à)F˜JFÿ÷{ÿFˆ± Fðø6àßø@°
-ÿà6
-à-Ð I F"yDðžúP¹4%'F48xðWø
-à›1F…`BF
-úDJ¹€#F
-
-‘ûDð†øP¹™#
-˜qÿ÷Óý๱#
-˜1ÿ÷ýع@ò
-±"
-àPF×÷ßÿOôÊs
-±h³¹Oô¹s
-˜™ÿ÷äû
-˜™ÿ÷™û
-
-ñ à×÷~ý8`
-à#I0FyDð9þ0¹ñ
-x
-h“B,Ñ+*Øßèð #
-±ð˜û#h
-I F
-hhhÀpGh
-hhhÀpGChÛÕì÷ä¼pGsµFN~D3hs¹HxDðPüF0`8¹T#
-KA"{Dè÷²û(Fÿ÷Ñÿ F
-M}D(h
-ž‰FFšFð-Ð
- àHFYF"ð}þ@¹™ø *±ñ ñ “ à$K‡"
-à5 à)F8lðïÿ!Fÿ÷ªþ0¹58lðÕÿ…BñÓ
-Ã
-Â
-
-I F "yDÖ÷·û Fihó÷qü 8½
-à F™*FSF×÷ù
-hhhÀpGhhpGjFµðÐAjð
-ÕÓjð ¿
-Ñ£#
-M
-I{Dh}DyD ð×þ(4ÿ÷Lþü,ùÑK
-Ü‚(ÐÜ(6Ñàƒ(Є(1Ñà´(Ð܉(Ћ()ÑàPEÐXE$Ñà£jCðà£jCðà£jCðà£jCðà£jCðà£jCð 
-à£jCð@à£jCð€à£jCô€s£bñ8F ð*ý€E³ÓoK8FYø ðWý
-ÝÇ#
-K {Dæ÷vù(Fÿ÷ÿ Fÿ÷2ÿ
-Ü›
-áTãZp#i3#a ø½ê÷‘¹µF€±@h±ê÷Šù h±ê÷†ù h±ê÷‚ù F½è@ê÷}¹½-éðEF€h…°FšFÝø0€ Ÿž
-0$~D
-à7NOð
-
- $
-Íø
-àM±chCô€sc`à¨!FÕ÷ýÿÇç F°0½
-*®Ñ÷çÿ÷åûF F±¹OôÆs
-àÿ÷ØûFH¹OôËs
-ðúÿF¹ F,FÓ÷lú F°0½0µF‡°F¹oð
-
-
-
+ºñ
+çÑOê'€ø
+’ €ø À‡sÂs2
+Bt2 ‚tj
+BêTT
+ ‚v
+ DvÂvšBêQšBwš
+› w‚wÃw °½èðü†
+°½-éðO­õ}¯F "8­8Fðú;x!F¬.F F#ð;pûðCð@ûwþ÷’ý$¨ÿ÷Éÿ.¨ÿ÷®ÿÌÆÌÆ”è
+)Øшš·î[¢û‰‰šOê˜jOê™kJê‰(ð|Hãû«Íé«šPš@êÂQŠšãûÍéšš@ê‚‘‹šãûÍéšPš@êÂQŒšãûÍéš š@ê‚‘šãûÍé
+
+šP š@êÂQŽšãûÍé  š š@ê‚‘šãûÍéšPš@êÂQšãû‘š†FêƒFãûg"p|@êÇ&ð~F ûûëF›OêbAñ
+š a"ð~@ š`a"ð|@š a"ð~@àa+ð|@ b Tø! î*ðÂñ¸îgk
+)ÛÑt©(F~¯.®þ÷Qù"FL©8Fÿ÷ ú2F© Fþ÷­ü:Fˆ©0Fþ÷¨ü
+ÿ÷¡ý™8Fþ÷•ø•J9FHF ñ ,­OðzD€2þ÷ïû"F9FPFÿ÷bøQFXFÿ÷¶ú"FIFPF6¬ÿ÷NùQF8Fþ÷vøRF9F8Fþ÷×û9F0Fþ÷møRF1F0Fþ÷ÎûZF1F0Fþ÷Éû1F(Fþ÷_ø)F Fþ÷[ø!F Fþ÷Wø"F1F Fþ÷¸û"F)F(Fþ÷³û)F(Fþ÷Iø*F!F(Fþ÷ªû)F Fþ÷@ø!F Fþ÷<ø¸ñøÑ*F!F(FOð þ÷˜û)F Fþ÷.ø!F Fþ÷*ø¸ñøÑ*F!F F õ€xþ÷†û!F@Fþ÷ø#AF@F“þ÷ø›;÷Ñ"FAF Fþ÷tû!F Fþ÷
+ø #!F F“þ÷ø›;÷Ñ*F!F(Fþ÷bû)F Fý÷øÿ1#!F F“ý÷òÿ›;÷Ñ*F!F Fþ÷Pû!F@¨ý÷æÿc#AF@F“ý÷àÿ›;÷ÑAF"F FOð1þ÷<û!F Fý÷Òÿ!F Fý÷Îÿ¸ñøÑ*F!F(Fþ÷,û)F(Fý÷Âÿ)F(Fý÷¾ÿ2F)F0Fþ÷û:F1F0Fþ÷ûZF1F0Fþ÷û1FHFý÷«ÿRFIFHFþ÷ û FZFIFþ÷ÿ Fÿ÷jüx± FZFIFÿ÷lø Fÿ÷aü0»J1F0FzD¨2þ÷óú@¬1F Fÿ÷ûšø
+F1Fÿ÷1ø"F1Fñ(
+
+F!F
+¯þ÷ÍÿBF!FPF¬þ÷ÑþJF1F F­þ÷Sú ñ(QF8Fþ÷Múñx ñx(Fþ÷FúñPèF ñP@Fñx þ÷<úBFAFHFþ÷¥ÿ:F!F0Fþ÷ªþ:F!FPFþ÷›ÿIF Fÿ÷ùø*F!FñP
+
+F!F
+¯þ÷zÿBF!FPF¬þ÷~þ ñ(1F F­þ÷ÿùJFQF8Fþ÷úùñx ñx(Fþ÷óùñPèF ñP@Fñx þ÷éùBFAFHFþ÷Rÿ:F!F0Fþ÷Wþ:F!FPFþ÷HÿIF Fÿ÷¦ø*F!FñP
+RFðëØ
+OúŠúòÑ ñ XF õøyÿ÷âú
+ÿ÷“úAF õË`ÿ÷4þ õü{œ«Oðx ¬AFF“ÿ÷}üOêZ FV® û±ÿ÷·ø!F0Fÿ÷Zþ1F8Fÿ÷þºñØ!F û
+°ÿ÷5þ:FAF Fÿ÷jþ!F0Fÿ÷Eþ1Fñ 
+0ÿ÷þ
+ñ
+õ wºñÉÑ(FOð
+ÿ÷VúñP
+ú ð
+
+“› “›ñ
+üÀóÔ “› “›ñ
+
+›Ãñ
+•vKÝé‰ãû‰tK¦û#fBÍé‰Ýé‰ D3™Q3‘Cë4‘ÝégKàûjHÍéÝé&ãûÍébJâû‰bJ¤û#U3D•ÝéCë]K•ãûF
+F¤û
+š«ûgáû š™ë ™LFUFÝéšàû šÍé
+šÝéšãû šËñ
+ŸFEñ
+ ŸÍø0 šF à
+
+&“›õ€›OêT[Cñ
+›OêT[OêTZCñ
+
+›cë ›õ€›OêT^Cñ
+“ F™±ë™ÍøØàaë9“›õ€›OêTUCñ
+žAëf Íø0àF›v›$ž“›cë“›õ€ ›OêUXCñ
+JÍøh {AŸ“›§û«YB›û›D›ëºF“ O ›Kë “ªû#žÍé # š à,
+
+ÄN šûŸBë
+š§ûgD™ë
+œGëÍø0°Íø8€ˆFºI¨ûgûw(œ1œG뜣FµL«ûgûwš0Gë²O¢ûE
+š“FûUšë Âñ
+šûRœ ’š ›
+šCë—Kûwš¢û#ë
+
+;DCë õ€OêWS’Hñ
+’šIë’B &˜R´ë eë*’ šõ€OêRZCñ
+šOêQWOêGWBñ
+šbë šõ€šOêPTBñ
+’šbë’šõ€ šOêQ[OêQZBñ
+’ šbë ’ šõ€šBñ
+
+°Mû4¢û#Íé#›š#D“
+›œÒ›Dë K OêhTCêÈ#Áó“OêPSDëCêÅ#ië Àó
+“Aë›OênQ “Oê\SCêÎ#ÝøàßÌóOêWTAë OêiU“DêÉ$Çó“wF¦ÍøPàOêVQEë
+
+OêjSÍø`àAêÊ!Íø€àŠCë T ÆóOêkX“DêË$&›Âó 0švFä+›OêTZHë›JêÈ*Oêh\Íøpàë
+›OêZQLë Äó“AêÌ!,›OêlUÉ-›CëÊó“K hòFCêÅ#›1šBë
+˜ HLpFEë
+;H¢û
+žsA“›^ ›FêÃ&[4Cëc nCêÅ#šOêRWFë OêkS(žGêË'UFOêWXCë›HêÅ(mëSFOêX^Eë"NêÃ.[ à-
+
+ Oêi[CêÉ#ë OêYSKë
+OêfZCêÆ#)ž›ž“*›JëßøP¡“›p
+spJNê@êECêA›™pÀóÑ™ËpÀóÉ# q
+êŒÀóÁ@›C™HqÌóŽ˜Ìó†<q˜<IêÀLê ™øÀÝéIOê0
+C™ÚsÇó’tÇóŠ"ZtÇó‚G!JêÈCÈóOÚtOê"OêX8FêNšuÅóÑŸtvÅóÉ"ZvÅóÁEƒø€ƒøà
+ꉚ+C“vÉóŽÓvÉó†3šCêšwÝé#[Oê2›Jw[
+‹w›[ Ëw;°½èðàÿÿ€ÿÿðÿÿþÿ?
+“ü÷¯úÀóÔ ò½ “ü÷¨úÀó ò¿ “ü÷¬úÀóT õáp “ü÷šúÀó”q¨“ü÷ŸúË OêÐ FJêAj“ü÷‹úÀó õ•p“ü÷úÀóT ò-ü÷~úÀó” ò/ü÷ƒúÀóÔ õ™pü÷}úÀó ò5“ü÷kúIOê0
+›Fáû‰0™
+™æû#™™F ›Fáû‰4™
+™åû# ™æû#™™F ›Fáû‰5™
+™äû# ™åû# ™æû#™™F ›Fáû‰6™
+™ŒF™áû # ™OêÞäû# ™åû# ™æû#™™F›Fáû‰
+™˜ëû# ™àû# ™äû# ™åû#™æû#™ªûF™Fš›ûë
+™˜àû# ™˜ëû# ™àû# ™äû#™åû#ªû™F›Fûžë
+™˜àû# ™˜àû# ™˜ëû# ™àû#™äû#ªûû˜5•KA™6“›£û#
+™˜àû# ™˜àû# ™˜àû# ™˜ëû#™àû#ªûû˜”KA™“›£û#
+™˜àû# ™˜àû# ™˜àû# ™˜àû#™ëû#™ªûû7”KA8“›˜
+™£û#
+˜Cë
+› ™£û#
+ûñ>“ªû4û Íé
+“
+êŠ,’!šbë
+"’$šõ€%šBñ
+ê‚0’%šbë $’&šõ€'šOêP\Bñ
+šOêUQBñ
+šbëõ€D’OêVRNñ
+Cñ
+
+›8™cë ›õ€›Cñ
+“›õ€ ›>šCñ
+
+Eë ©M”ûg©ûE=DŸë ŸEë¤O”©ûEûU2™a¡L‘™Eë‘™ûf™©ûE5D•Në ™ÍøEë £ûE&™Íø0Ãñ
+~LEë
+!F£ûEû
+
+¢ûEšë DÍø,ÀEë šÍø4À™”FFJ¬ûE¼FFOûU0š$™¢BLEë#F¥ûEû U›ã“Eë
+›ëœÍøPà5DNEë
+Íø\à¤ûEûUIžëžEëžM±F.F©ûEûU¢Eë ™ŠFIªûEûU›™ë
+Íø  Eë
+˜Íø8 
+MDB
+˜‚FH
+C¡û
+
+›ë šFûÆMAëÆO“›û
+D£ûë !D“›ÁLAë“
+
+@ë²ë ’iëõ€ ’OêPRCñ
+’B R²cë›"’šõ€›OêQXCñ
+›šcë “ ›õ€ ›OêTQCñ
+›OêQ[Cñ
+ FÍø
+›cë$“›õ€›OêQPCñ
+“›õ€›Cñ
+
+G˜4F¢ûgûw½Lë
+¯NGë˜Íø@€û˜¢ûgGDë
+
+GDGë~L£ûgû
+˜£ûg›ë›'DÍøDàGëmKÍøHà¡ûgû
+˜ “›ž ›Cë¡û#û
+›Íø4ÀÁñ
+ŸCë TH¡û
+
+RJ
+3D”Cë”Nœ¤û#œû3CœDœCëœKF¤û#œû3œQCë
+
+Eë¢L—
+—ŸNëOêV^—OêN^±ë—`ëõ€—OêP^Eñ
+ŸOêQROêQ[Gñ
+Ÿgë
+— Ÿõ€ ŸOêQ\OêQPGñ
+—Ÿgë— Ÿõ€ŸOêQ^Gñ
+Ÿ@ë
+—Ÿ·ë
+—Ÿgë—Ÿõ€Ÿ à
+
+´L˜MDEë
+
+OêZPBë Îó@êÉ ’OêiRžFBëÊó’b hBêÅ"QÄóOêQW@ë ’OêkYšGêË'Áó ¿šOêWZIë šJêÉ*OêiXë
+šOêZQ“HëÇó’AêÈ!šOêhPŸ‰
+“Bë
+
+OêhYCêÈ#ëIë
+FOêXSOêbYCêÂ#š›š“Ië
+“›ßøx‘ƒø @#
+‚ø!0 êE êACêDÅóÑ‚ø#0ÅóÉ#‚ø"@ÅóÁEML‚ø$0›êŽêˆCšƒø%PÎóŽÎó†>‚ø&0›DJêÛNêƒø'àÝé#[Oê2›…ø( =JÃóK#…ø)0›êÃóCCC…ø*0Æó…ø+0Æó3…ø,0Æó
+Oê\<IêG…ø60ÁóÑ…ø2
+…ø>0›[ …ø?0 õY}½èðüÿ
+ü÷šü!F(Fü÷uüPF)Fü÷4üRF F1F öè
+ü÷‹ü!F(Fü÷füPF)Fü÷%üRF F1F öˆü÷|ü!F(Fü÷WüPF)Fü÷üRF F1F ö(*ü÷mü!F(Fü÷HüPF)Fü÷üRF F1F öÈ*ü÷^ü!F(Fü÷9ü)FPFü÷øûRF F1Fü÷Qü!F(Fü÷,ü)F öh0ü÷êûN¨ÿ$ü÷<øX¨ü÷Qøb¨ü÷Nøù0“¹ù0{¹ñÿ4öÒN©8Fü÷cú "™8Fã÷Fÿ°ú€ð@ ùæN«“UK{Dõ›c“”­™(Fû÷Tþù0
+ëÚzOêj
+
+û*2Fû÷–ûž«2FF*®YF“ ñ€ û÷–ú
+ñ()F0Fú÷þRF™XFú÷þ4«ÚªF
+ñP“ õ2zú÷ þЪPFFû÷rûZF1F(Fû÷wúZF1F˜û÷hûQF0Fû÷Æüš1F¨¨û÷iúš1FPFû÷Zûç
+Ò›
+þ›F+ÑرK˜BÐKœBÐK
+Hà
+K"
+HOôêq{DxDè
+
+
-Oð
+Oð
K"
-Hº!{DxDè
+H»!{DxDè
K"
-HÄ!{DxDè
-±ðù¼FpGK{D`pG
-J
+HÅ!{DxDè
+± ð»FpGK{D`pG
K"
-H@ò{DxDè
-K˜BÐ K" H@ò{DxDè
+HOô™q{DxDè
+K˜BÐ K" HOôq{DxDè
+ðúÿ F>½0ÿÿPÿÿ
+ðÓÿ F½
K"
-HOôžq{DxDè
+H@òg{DxDè
+𮿰½z4
+J
+J
+ðùþ#hJ“BÑ
K"
-H\!{DxDè
+H±!{DxDè
+ð³þ F°0½
+ðŽþ F½
+ðfþ °0½¾
+ð(þàLáç F °½èð
+ðâýÝéE
+ðËý^¹±›;`¸ñ
+þF Fÿ÷þ­¹-Ñ©) AøMð^ïFø±K@ò5H*F{DxDè
+HOôžq
+K"xD0{Dè
+ðrý°0½0
+ðJýà›+` F°0½
+ð$ý ›ÚÕK
+ðý(Fð¼ìFx± K" HOô³q{DxDè
+ðûü °0½
+ðÒü ›ÙÕK
+ð¾ü(FðtìFx± K" HOô½q{DxDè
+ð©ü °0½
+ðxüûiÛÕ(K
+ðdüûi˜Õ K
+ðPü"F0FIFÿ÷ý"F@F1FðìF± K˜BÐK"HOôÊq{DxDè
+ð1ü Fñ$½F½èðƒ
+ðìû„è §`½èü
+ðÆûð
+ð²û„è §`½èü
+ð~û›ØÕ&K
+ðiû›™ÕK
+ðTû0F)FðëF°± KœBÐ3œBÐK"HOôòq{DxDè
+ð7û F°p½
K"
-H@ò_{DxDè
-K˜BöÐ
+HOôáq{DxDè
+ðÿú °0½
+ðÈú F½F½èð
+ðý ©—•”ðfìp¹ ©” •%—Íø(ðZì ›F3`p¹3à« F
+ð]úàL
+ðœü ©—– ”ðèëè¹.›!
+” —“ –Íø4Íø8°Íø< ðØë›F ±+`à"©) Aøp=ðÌëF&»Ià.›ª’ FÍø
+ð´ù±(h1Fÿ÷Gú
+Ñ©' Aø]ðRëF(Fÿ÷úà(FðÔéFœ± KœBãÐ
K"
-H@ò
-!{DxDè
+H@ò¾!{DxDè
+ðiù F°0½
+ðF¹°½ª'
+ðžû©& –—”ðêêà0F)F"FðxéFð±K˜BÐKœBÐ3œBÐK"H@òî!{DxDè
+ðýøàLåçLãç F°ð½
+ðÆø
K"
-H@òS!{DxDè
+HOôEq{DxDè
+𞸰½\&
K"
-HOôq{DxDè
-–
-àFšF£k˱gk1Fàj»B4¿ÃëÃë¯B(¿/FÀ:F ðµü kak8 c ðàý
-ë™BDÓckàkñÿ<[BÈë ŒD© ê
-¿ñÿ1ÈëÈë[B¨D1Fê
-àKœB
-‚álKœB
-Ø£õ€SœB
-à=F»FOð" #:Fà
-Ñðk)F*FðÞé
-ð»þ
-
-ð}þ|¹ K" H@ò‘{DxDè
-ðlþÍÄ•è
-›£b³iãb
-ðþýàMàKBéÑ(F°ð½
-ðÚýàiô€%ÑK"HOôÿq{DxDè(
-ðÆých
-FðÂèFx±K"H@ò!{DxDè(
-ð«ýãiCô
-ðKýàKBèÑàMèç(F °ð½
-›ššBCÑÝø €#iCE>Ó jþ÷)ý`jþ÷&ýãi9F j#ô€#ãaþ÷fþFP»`j1Fþ÷`þF±KBÑ&àãiÄø€Cô€#ãa àKBÐ3BÐ3BÐK"HOô4q{DxDè(
-ð»üàKBâÑàMèçM(F°½èð
-ðü*h#hšBÐGK
-ðxüch+Ðãi(Fô€"¿!jFbjÔÿ÷Ôþàÿ÷/ÿãi•ø0 ëacika£j«b”ø00šBÑjkckšBÐ0K
-ðEüïjæjDZ~¹'K"'H@ò÷!{DxDèH
-ð1üèjáj¢k
-ðPþ£k«cà~±K"HOô?q{DxDèˆ
-ðüákèkðïF±K"H@ò1{DxDè
-ðÿ»°ð½'‡
-ðÌû%àk¥b9F2FðÔîF± K@ò#1 H*F{DxDè
-ð°»°ð½
-ðtûàK˜BëÑ F°0½
-ðOûch+Ð(K
-ð;ûãi[Õ#jƒ¹K
-ð%û£j± Fÿ÷3ý&àk¦bAF:Fð>îFx±KOôXqH2F{DxDè(
-ðû
-ð÷ý•ø00û
-A{DxD
-ðŠúàLçç F°½èð‡
-ð9úàLèç F°0½
-Ðõ€s˜BÐþ;˜BÐõ€s˜BѨkik 
-ðEý
-ðªùàKœBêÑ F°½èðƒ
-ð}ùch+ÐK
-ðhùãiZÕ#j‹¹K
-ðQù£j± Fÿ÷_û# F£b9F2F°½èð@þ÷i¿
-ðùch+Ð.K
-ðùàiô
-ðòø£j+ÐK
-ðÝøàk1F*FðèëF˜±K"H@òËA{DxDè
-ð¸°ð½
-ƒ
-ðtøàK˜BêÑ F°0½
-ðTýÀ¹¬bà LK"H@ò)Q{DxDè
-ð1øàK˜BÐéçL F°ð½
-
-žzD
-ë èkéjªkð(ê›FÈø
-,J¯Íø (F™X#FÍø
-H±¹ñ
-;˜BÐK˜BÐ3˜BÐK"H@ò²a{DxDè
-H±¹ñ
-;˜BÐK˜BÐ3˜BÐK"HOôÛa{DxDè
- 9Çø°ý`{`»lÇø {aûl»aØø
-H±¹ñ
-;˜BÐK"H@òOq{DxDè
-LH"Íø @òaq{DxD
-2H"Íø Oôía{DxD
-(H"Íø @òjq{DxD
-±¸ñ
-p
+H@ò!1{DxDè
+ð~¸°½&
+ðYø F½
+ð ø F °½
+“—–ðÂé
+›F à+h!F8F2F“
+àFšF£k˱gk1Fàj»B4¿ÃëÃë¯B(¿/FÀ:F
+ðüø kak8 c
+ðEú
+ë™BDÓckàkñÿ<[BÈë ŒD© ê
+ð¬øàj1F£k*FÀCà¼FàOð
+¿ñÿ1ÈëÈë[B¨D1Fê
+ð`ø£kÝø À]¥cŸ
+à„KœB
+Ø£õ€SœB
+@"à/@ðÍ€
+"à
+"SFà
+Ñðk)F*Fðê
+
+›£b³iãb
+FðþèFx±K"HOôq{DxDè(
+›ššBCÑÝø €#iCE>Ó jþ÷ü`jþ÷
+Ðõ€s˜BÐþ;˜BÐõ€s˜BѨkik  ð´ù
+
+
+bFþ÷òúF
+H±¹ñ
+ùXFð%ù¸ñ
+;˜BÐK˜BÐ3˜BÐK"H@òÙa{DxDè
+
+H±¹ñ
+;˜BÐK˜BÐ3˜BÐK"H@òÿa{DxDè
+
+
+ 9Çø°ý`{`»lÇø {aûl»aØø
+H±¹ñ
+;˜BÐK"H@òvq{DxDè
+LH"Íø Oôña{DxD
+2H"Íø @òq{DxD
+(H"Íø @ò‘q{DxD
+±¸ñ
K"
-H@ò¹q{DxDè
+HOôüa{DxDè
K"
-H@òÉq{DxDè
-
-±Ñ`à HxDA`ÙhF
-`ü÷Ûü JzDh;`3¹½è@»÷˾›h
-
-
+HOôþa{DxDè
+±Ñ`àHxDA`ÙhF
+`ü÷Íú J KzDãXh[iR¹ð+нè@µ÷¹›h
p ã
-H œxDè
-ðs¹‰
-ðpùK(F”è
+H œxDè
+ø
K"
-Hº!{DxDè
-ð¹¸
-ðÙ¸ ð ½µðeü
-F{D ð—»
-ð¦ø¹HxD
-ðŠø
-ðÍø F
-ðxø
-ð]ø
-ð«ø F
-ðJø
-ð-ø
-ð™ø F
-ðø
-ðƒø˜
-Fÿ÷¿pµF FF!F ðÁÿ
-ðc¸
-H LxDû÷íù K" HA!”{D
-à[h
+Hº!{DxDè
+F{Dð³¿
+Fÿ÷¿pµF FF!FðÝû
+H LxDú÷ïþ K" HA!”{D
+à[h
+ò
l2
-d@¹VH@òE2UIVKxDyD{D àPø,
-BIKxDyD{Díçƒ`Oð
-à B ÓlH@ò›kIlKxDyD{DB3ú÷fþú÷xþ&.ØgHOôÏrfIgKxDyD{DîçSø,8Sø<£±ÀAh™BÐ`H@ò­`I`KxDyD{DÛ狲C`Dø<Dø,à²1FDø,¤ñÿ÷9üWK{Dh–
-"*I*KxDyD{DN3Aç F)Fÿ÷’ûàF
-àVø5pÎç ø½
-تBØ‘BبBÓ3³BîÑ
+d@¹VH@òE2UIVKxDyD{D àPø,
+BIKxDyD{Díçƒ`Oð
+à B ÓlH@ò•kIlKxDyD{DB3ú÷hûú÷zû&.ØgHOôÌrfIgKxDyD{DîçSø,8Sø<£±ÀAh™BÐ`H@ò§`I`KxDyD{DÛ狲C`Dø<Dø,à²1FDø,¤ñÿ÷9üWK{Dh–
+àVø5pÎç ø½
+تBØ‘BبBÓ3³BîÑ
ø; ñ œø
ܸñ#fиñ*fиñ @ðÁ‚Xà¸ñ.jиñ0иñ-@ð¶‚_à¸ñU
Ñ3h6Cêã{jç
ø‹
-`H`"àø
+`H`"àø
á
›AêEqñ0
"
@@ -2876,113 +2767,120 @@ BIKxDyD{Díçƒ`Oð
ø8
àºñ
ø 1YEòÑ{õ†¬œ #¢àºñ
-ø;:
-ÛªÇõ€qÐ1JzDÿ÷ÿ
+ø;:
+ÛªÅõ€qP/JzDÿ÷¨ÿ
È¿$þ,(¿þ$+U
-+úÐ,
-ÐJh01
++úÐ,
+ÐJh01
F
-±Øø û šB FAFû ú´¿ºh
-¨ðéüö8A0Fð‡ú_êÐz1F ˜Oð¿ ñ #F ¿ ëÛ{Oð Oð
+±Øø û šB FAFû ú´¿ºh
+ÿ
+¨ðùö8A0Fð±þ_êÐz1F ˜Oð¿ ñ #F ¿ ëÛ{Oð Oð
˜
-˜!ð=úF¹±
-˜ ™“ðú›˜±¹±7OEñÚ ›
-˜”
-¨!Fð?ü ¨!Fð;ü ¨!Fð7üà
-Ðch"ú
+˜!ðgþF¹±
+˜ ™“ð;þ›˜±¹±7OEñÚ ›
+˜”
+¨!Fðiø ¨!Fðeø ¨!Fðaøà
+þ!FF ¨ðFø
+Ðch"ú
Fÿ÷ýKFÙF›F;F
-ñÿ:/FFºñ
+ñÿ:/FFºñ
¹74
ëÅ
ø50€½èü‡_(
Ð (Ð
-(Ð (аñ HBHApG pGAò
-ø@6øKàßøð úD Fÿ÷•ÿF
-Ð{h[B{`àOðÿ6à JzDxéç0F°½èð‡
-BûÐ
-ø  ø ø0ªŽ\>±ÁñHFQ2Fðßÿà1)ñÑ
-ñÿ1ë…
-h
-û>½8µF
-ñ?›“
-• ”¬ ñˆ5•ú¥ó•³úƒó “ ñ@Ë„è
-šÌëÌëÝé @7«Óé
-šY@³Óé
-ðÚøJ«ž€#øð<ÝéÝé#D@:¨M@ˆê
-‰ê Áé
-õ¸v1F F
-õ!rÍøÀ¢÷×úÚøp1Úøt!ÝøÀº
-õÀsº/Æé
-õ¸qbFÿ÷bÿXF°½èðOô^pü÷¿ºü÷ʺµ
-’Ë$mAvAA(¿„ð‡Œè
-1º8º#º*º‘ë ’ ñ “¹ñðé
-F“•Ÿi³&¬YF FÍø Àÿ÷ìþ”è
-ñ?
-_êª
-•eFÍé‰ ñøÍø  ñ@Ýø(—è
-yˆè
-Ýé#ÍéÝéB@K@~©Áé
-ŸK@B@€©Áé
-#„«Óé
-
-vé\E‡è
-‰Žè
-E‚êƒê `@i@Çé
-té\‰…è
-0Ýé4#ÔéÔé
-xӏ
-E|¨l¬Ðé
-‰Ýé
-‰F@O@ÕéÍé
-#F@O@Íég{@Ÿr@ÕéÄé
-gF@O@Íégp¯×é
-gÐé
-gÝég‰ê x¯×é
-ñ@
-ÝøÀp@y@Ýé
-gê €ê
-‡ê Ðé
-ƒê Äé
-…ê Áé
-ƒê Çé
-ƒê Çé#`@i@Çé
-Äé
-JF8FÍéE×éEðYø×é#ÝéT@]@×é
-
-à *FÍøÀ48F¡÷¶úÝøÀ´BòÑ,%Ð,Ð,cÑAàr¨b©Ðé
-#Ýé(gr@{@Ýé&gÍé(#t@}@Íé&En¯^¨×é
+(Ð (аñ HBHApG pGAò
+ø@6øKàßøð úD Fÿ÷•ÿF
+Ð{h[B{`àOðÿ6à JzDxéç0F°½èð‡
+BûÐ
+ø  ø ø0ªŽ\>±ÁñHFQ2Fðüà1)ñÑ
+ñÿ1ë…
+û°Ð½´# FF F]øKÁ÷ »
+ù°½#µF ëÁ÷ù±›#`°½µF³÷êÿ F
+¿Oð
+ЛšEØÑ›œBÜ
+ûJOð øKçç.F»ç+,¿µtxFÃç Fð¾ûX± Fðäû
+¸ñ
+'žçÿ÷z¿-éøO€F‰F›FW¹
+º@FëR
+› û•)F˜G
+,¿#
+a“ø%@“ø$
+D“B¿Oðÿ3`pGhF@hih‘B$¿‰˜h¿÷Þ¼ChihhihDpG8µF h+ihšBÒF(F¿÷ËüÈ„è
+hh“BÓRØðpC³ñ
+“ˆê“Ôé#Uø8r@Šê‚ê Uø4 “ƒêUø@›ÍéÎA@ÔøXà‘Uø<‚êÔøTÀ†êY@ ›‘ámK@Uø(J@Uø$’K@!m“›H@ƒê Uø0<X@Uø,<Y@Íéˆê #mUø ‰ê ãm€ê
+›Íé £ XZh‰ê
+V@UéUé@5Šêp@ê ‚êÍé!Íé  š ˜ÿ÷@ÿ›š™Z@›K@™J@™K@™J@™K@
+×éN@×éŠêp@Íé#ê ‚êÍé-“*ÙÔé# ñH=‰ê ˆêÔé#Šê
+›V@ë øXÜéÜøÀ€ê
+š€ê
+Vºº2º+º’[A@AIA(¿‚ð‡ººº‘úüÄée’[A@AIA(¿‚ð‡ººÄéeñðÄé Ǻ‘úüÄéÇ’[A@AIA(¿‚ð‡ú€ü‘úþººÄéìÄév4¥BëÑ
+F“Sñ±®F0F
+“Q@
+š ›B@Íé<‹ê Vø,›‹êVø,ŒêZ@Íé>š ŸVéì@6’ú¢ò“²ú‚ò2 X¡Jhx@
+˜€ê Ñé'VøH _@›‹ê’‰ê ƒê›Íé@ƒê
-* Ð* Ð:PBPApG*ÐXBXApG
-Û)Ý)Ñ
-Ð.+Ð/+Ð:+Ð=+Ð?+¿$ð€ñ¿%ƒ\ ¹± àŠBÎÑúç
-h“BÑ+Ð+Ð+Ñà@hIhÞ÷Õº@hKhÀpG@hIhÆ÷[ºOðÿ0pG
-+Øßèð
-
-i±Òh
-±G½ FF½è@ÿ÷·¿-éðG FF iF
-x±h
-h FðÐh
-!¡÷§üC4Ð( Ð(Ð#hCðà#hCð#`
-Fø@ø0#
-ÐE4¿GFWFø0 F«÷hû
-F F«÷Aûð±¨1FRF«÷ËûÀ±¨1F
-œAF:F(F3F
-#£jꚢbÝé#Bê  Fê7 ‘
- —Ýé #Að€qãjêšâb
-gaiåû
-Cñ
-ñ
-ñ
-Ðñ€B:R’
-àBhRø# ŠBÑF½è@ÿ÷Ï¿3£BòÑ
-ÐFÄ÷šÿF(±#hXhÄ÷„ÿ#h]`(¿ 8½8½ ±
-ÐFÄ÷ýþF(±#hØhÄ÷çþ#hÝ`(¿ 8½8½8µF±hiB
-ÐFÄ÷æþF(±#hiÄ÷Ðþ#ha(¿ 8½8½8µFh
+S@Vøh,“Vøx<ƒêVøt<Vød,Z@VøX<Y@VøT<A@˜Z@VøD<Z@›K@!“›S@š“ÿ÷Ÿû›6™7š4˜Y@›Z@›Eé:™€ê ›5˜;šX@ ›EéÀ8˜Y@›Z@ ›Eé
+?™€ê ›9˜>šX@›Eé À‹ê ˜ƒê <™
+›H@=™Y@EéEé,›Bš@™˜Z@C›H@A™{@Eé#›ê Eé@5;“ôè®›Tš›ë ˜D›Íé 9›Íé"7 «Ë„è
+
+{@“Øø0Y@Øø 0Z@›K@“›S@“¹ñ@òÔé!5"› ñ l#ŸZ@ ›O@ëƒê
+C@“‚ê #›Nø !šK@“ëz@©ñZ`ñ šš`šÚ`›ƒê “›C@“›K@“
+›Z@›’šZ@Ôé
+’šP@šS@ÔéÍé"H«™D «O@V@Íé v©ñP ˉè
+Fø õ!rÇé0Fy` ñÿ÷ú×éÔéR#hB@K@Vø
+#L@=™A@ËéA:›*š+™(œZ@;›)˜K@8™Ëé#L@9™A@ËéA¸çT›"˜ð™ü›3“Æç-éðOË°šFX›F
+’UÝøX±±W› ¹ªñ
+ù±®
+F0F!Fÿ÷Üû–è
+ñ?› “
+›ñ@› “ ›“õÈs “6«“B«“ÔééšÔøH€ál‚ê Uép’š ›‚ê’3š “›J@’šƒê“W@šP@UéÍé8pê ™J@Íé6ÂÔéƒê›S@Ôé“›K@“›S@Ué
+“›ƒê ›Ué Z@›Íé<Âx@šY@Žê “›Íé:‰ê ›ˆêãlS@U铈ê Z@Ué ›Íé@Âê X@ ›Íé>“ú£ò ›²ú‚ò2 X¡JhC@“‰êÑ铈ê
+ ˜>Ÿ›€ê?Ÿ@˜‰ê Ÿˆê
+›«DD›"“›#“›$“›%“"«Ë„è
+#Oê$˜"™#ŸP@%šS@"jÍé$"¨J@ajO@Íé"'¯õ!r9F˜÷®ý›ë BF8F“›“ ›“!›“ð4ú š›™˜S@!šJ@™Íé 2J«CD€"H@™i@Íé9Fø°, ë
+F™Y@Íé !õ!r)F˜÷$ýÔéP#™ ˜Q@šZ@ÔéR4ÍéX@!›c@WœÍé 
+ŸæOð
+#h@˜H@™Q@š‘Z@’*›:;™<š]@+›-˜Y@,›ËéQZ@=›C@˜Ëé#h@˜H@™Q@š‘Z@’Lç
+›SDFW›FÐ\ì\3+€ê
+Ñð
+Ð:PBPApG*ÐXBXApG
+±)Ñ(F!Fÿ÷ßÿ à)FÑÙ÷“üF
+h“BÑ+Ð+Ð+Ñ@hKhÀpGIh@hÙ÷Ô¼Ih@hÇ÷¼Oðÿ0pG
+€%Oð
+Oô
+Oô€5Ëçµ F ñÌ÷dÿ±ø0 #`°½µ F ñÌ÷¿ÿ8±½ø Fÿ÷ÿ± "`°½µ FÌ÷¾ÿ(± hÿ÷rÿ
+¹$Éç
+Áø
+!(hš÷õùC+Ð ð
+ø0
+à
+Ñ ñ .›™EáÓ0›¸D5Û0“šçøø
+›
+#ð|C@ð€pD#cckD`cÔø$€Ôø
+Î!jÔø0¨û
+#¦iÔø4°áû #áiáû#aiæû #áû #!iÍé
+ª3D"ø,
+3Äé 3£d½èðA
+‹°‹FÚøH "±
+ñ8PFÿ÷NþÚø$0Úø(ë“bÚø,#ð|C"ð|Gë’aÚø0 !ð|Fë‘aÚø4 !ð|Eë‘b"ð|D’ñ|Lë‚DSë“i#ð|Cë™hë˜`(ð|H ël ð|@OêÜqñÿ>IBê
+@C)ð|Cê@ê
+ñL
+ñP
+Fê‘ÿ÷ÑýÚø0 3Úø,Gñ
+ñT
+ñX
+©ë
+©" ë
+©BëAø ="
+©Aø=" ñ
+ÐFÆ÷úF(±#hXhÆ÷ú#h]`(¿ 8½ ±
+ÐFÆ÷ùF(±#hØhÆ÷kù#hÝ`(¿ 8½8µ FFˆ±hi‹B
+ÐFÆ÷jùF(±#hiÆ÷Tù#ha(¿ 8½8µ
+±Ch`pGChhØ÷›¹@hpG8µ FFp±Ch‹BÐFÆ÷#ùF±`hÆ÷ùe`(¿ 8½
+©:F
Ð
-(Ð (Ð (аñ XBXApG pG ña+ÙA8(Œ¿
+(Ð (Ð (аñ XBXApG pG ña+ÙA8(Œ¿
Ú°G
Zà6¹:hØø
ñÿ8ûX'ÙOêÚ ›(Fû ùOêI ë Éñ
@@ -2991,15 +2889,15 @@ h `:`à˜9F"F3Fÿ÷"ÿ›"“?GE
à6¹:hØø
Áë JZE¨¿ZF
Èë BE¨¿BF
-3Fÿ÷›þ£E Ý!FXF
-
-F±x1œB÷Ðx½pµ¢±à*Ñ(xxÀp½:
+3Fÿ÷›þ£E Ý!FXF
+
+F±x1œB÷Ðx½pµ¢±à*Ñ(xxÀp½:
JOð àOðÿ;øK×ç»ñÿ?бÊñ
¹ñ
-&¦çPF½èþµ1¹Oðÿ3S`àd
-ÿ(F!FjFÿ÷Éÿ
+&¦çPF½èþµ1¹Oðÿ3S`àd
+Àë ½èü
‘DÍø àÐøÀ;¼ñ
ëOð
› ñ Ëëë‰ G“Úà›Yh
@@ -3013,62 +2911,75 @@ JOð àOðÿ;øK×ç»ñÿ?бÊñ
ñ
ñ
ñÿ:©ñ ?™
-ñˆE¿ö¯à ñÿ;»ñ
+ñˆE¿ö¯à ñÿ;»ñ
àOð
-DEмB
+DEмB
à*Fàch
-
-FHhFÿ÷¿¿µ ±h’±Rø<±Rø Ì `Rø,F±ˆhŠS` iˆ` ±Hi˜G½pµ
-àRø#F
-ñOê… “
+
+FHhFÿ÷¿¿µ ±h’±Rø<±Rø Ì `Rø,F±ˆhŠS` iˆ` ±Hi˜G½pµ
+àRø#F
+ñOê… “
Tø!ë8
ðB ¿
þTø!
-ù‡ê Ãøë Ùø úùÃø¨B¡ñåت
+ù‡ê Ãøë Ùø úùÃø¨B¡ñåت
ê Ýø
û‹ê ÆøgEñáÓ5 ñ Tø%
-F
+F
Yø%:F5ÿ÷vÿPFshBóÛà
›Yø'
ë‡òÛ&êæv·
ëOD
-àñ *F6MFWø
-Ø@B½F½
+àñ *F6MFWø
+Ø@B½F½
œFF¨F!Fÿ÷Óù˜9FBF#Fÿ÷Dý1F
œFF¨F!Fÿ÷µù˜9FBF#Fÿ÷±ý1F
-œFF¨F!Fÿ÷—ù˜9FBF#Fÿ÷;ú1F
-9@9h:Ž:j ;Ã;Õ<à<ð=‘=>$‘>M?f‘?~@Ó†@±A|A›BUB¸2 ¥‘2 Ä2$“‰2$Ö3$ã‘3$ð4$’4$5$.’5$;6$I’6$W7$e’7$n8${’8$Ž9$R 2(jŒ2(" 3(}Œ3(^ 4(¬€4(ê
-90%90::0N:0b;0s;0Œ<0©<0·=0Ë=0Û>0ô>0?0‚?0&@02‚@0GA0W‚A0nB0{‚B0ŽC0‚C0²D0Ó‚D0æE0ù‚E0F0-ƒF0JG0cƒG0qH0‚ƒH0‘I0©ƒI0»J0σJ0îK0„K0 L0„L0)M0?„M0MN0c„N0uO0‡„O0šP0­„P0¾Q0΄Q0æR0û„R0S0'…S0?T0X…T0qU0Ž…U0™V0±…V0ÁW0Ò…W0åX0û…X0Y0†Y0,Z0;†Z0[[0j†[0‹\0§†\0³]0Ó†]0ï^0
-3@™3@+4@I™4@Y5@k™5@x6@„™6@™7@«™7@¶8@È™8@ü9@Ø™9@ë:@ š:@;@-š;@d
- W@ X@F X@u Y@¢ Y@¶ Z@Æ Z@Þ [@ï [@!\@A¡\@N!]@e¡]@£!^@±Š^@Ä!_@Ñ¡_@ß!`@¢`@E"a@}¢a@”"b@¥¢b@¶"c@Ë¢c@â"d@£d@)#e@@£e@X#f@‚£f@­#g@Σg@õ#h@¤h@H$i@v¤i@—$j@·¤j@?&k@b¦k@x&l@ó¨l@")m@J©m@x)n@Å©n@ä)o@ªo@/*p@Lªp@
-B
-BJ% BÃ¥ Bñ' B±¦ BË& B§ B'B¸'B^§B€'B;'B(!B›'&B×(+B…¨+B¿(,BD¨,B#(-B¤¨-Bj(.B©.B+2D:‡2DF3DT‡3Dg4Dx‡4D5D‰‡5Dœ6D²‡6DÄ7Dч7Dà8Dè‡8D
-²HP2IP2²IPH2JPX²JPx2KP‹²KP®2LPܲLPî2MP ³MP&3NPB³NPT3OPk³OPz3PPï†PP3QP:2Xü2hjŒ2h} 3h
-3h4hê€4hØ2l4Œ2lã3l
-2t¬€2tE 3t~ 2x“‰2xŸ 3xƒ€3x® 4xÉ4xâ 5xŠ5x
-6x/Š6x?
-7x`Š7xs
-8x…Š8x’
-9x±Š9xÆ
-:xÔŠ:xÞ
-;xòŠ;x <x‹<x5 =xJ‹=x 
->xRŠ>x”2|
-j
-å¦ÿ{Ý*þÔ
- þp'dø'úö_0¥ lÚòb^xGÓf
-ŠÀÝkÖÝGßÙØê|°
-à·‘J Ö.<EÉ‹yçÇ™:%…;Œ½ñ$ÿø%Ã`Ü7
-#þÑÔòÿaýÞþ¸eå
-Nÿ“Q²ÿ
-ÖYGžæ=6ÿD^¬«å:Õ°5ŸmºÀ…ôp?LPîÅëiþ˜B‡Îl)ª+1Â8{kîˆ ºÎ¨Ê`ñ%Ïcf»cë}ÊÒ´#ZoÑÜAsuÀý0‘Rh–E³f;S‰<i¼liãQãÒ„Õ(fµæ þm°ràŠÎae©!2HÜzá8Œuˆ=©Jo=Ÿ?½WkÎ?JÉÓùnr{[t꾜zmœ@Iæû*upåNítàu¬À±>ò¯ˆMf¶öO<lw®GQcšþá´ßéT;0*uãå)±L°|mµ®…Û8U–¥[Ÿ#(6¸¢A´×‘&>Êœz+`E†‹îdo\ MKZ°Ã&‹¸ƒiÏrb>^SOœsvüï t:ÐM·‡¡Ö‡llŒé DÄr>sÑN=ŽZ‹uËY,G‡Aþ馗&jµ»sª¸[ee[0žbYø¸2Á6R˜Jð«!^Þ Ú ™kžÀ¥ZÌ°·»Ò‹_Ó;>Œ¥qfã(Ôø?å'ßþ ²Š Z#a -õDñ\ø‚NÜxz«ÃW‘¯enqñD¿íCP´gHïZF´ ÈHí™zE¥’ÃiÖ׊ ë²ÿìmvøÂX›ò SÄt‘Ý-SÇnÐQ<¦}€ukßøjR»ø0EïQ…6¾ŽÏ šFè?™ý÷Ù>„åã7Ϙë^ZSw Üñ ™ì`@“ï\⥭*ÂÛkÁ~©#[Ù þ ¬(ºŽ’-@ƒL5Ðÿ˜Û
-&¸byœ Õåõ„MŽ]1~÷âÓ¡Aa]²šžTûÑa•Ê|IDt/ÊÄzá‹/»–îŠ]û>‚çÛ)îÉMšûŸŠ»7n(lùÿµµ‹ˆ ×ÊXöá2‘o6À­ÁW]v1CóÝìñ©yéé…בÇ1b<Ò,œ¤V7{¾@XÀƒ"èyÛ:1
-ã}Žz™µþt´Fr=½Ü½¯h q2ši;Çx“ñW—nðnE7Jô QõOg<Üì„íÐëÊûÛÿë¨#h‡dj÷Eà2!Y|P­V×i{Xø¹;¥»M‡F§m„E¾•Ò4͉•ÀðÓßnJã{Î@'Ç+«fY´{ÇÇð9š35¿Ì/ó.hS\ˆRãw¡'…Åt#“>ç..•ó Â%%99=nŽ‰½è»g^Œf‹c(Nt…¨¯]¶Šƒwv^bŠ§<¸W+¯6.²9´>um:¨15ÂÂy‰5&ÑÇ ùœ¦kµZ$m‘Å1ýÅúç¦ËK ”ÇîF’±²J+C7þ‰ïYs<vx˦ y_( [ŒžäªQšBoP=Ö!À™^è%€ëí]7G0p N C¾¶Gç*b]¦Å3bV$²¼fCÑhÕ;i¦ž¸|Õ¯>!1ë ¤˜òj^|›E²ÕŒ²§W_/OÛR™|X_ò¥öQ†!/[j®ƒ4mXKïþ¿s]ÛÄ—*…ólFB³ÁW—P5±·Ç<…mlýΰɢwîÃk 7ú0‘Ñ,¸^_‡ýZ0Nb¼eÆÎÏ+ªV>MϺb_šÐrÿï(½¾ØW=õW}éq1옔ÙT¿„ ãGšïóÛÃ\rží$ªdíç  |sº›†§;U«X0ñƒ/ùb„˜föU!Øò%dqKvYŪ“gÆ%«NKöØ?D.à½jò]õùSê¤ÈÙP3Ù¨-‘}*ÏÞ?
-Ò¼3²bSêwˆCf'C…é_Uõ*Š¬ßÿ›L–œ¥zÎÕyñ X•zçÓte ¤d0è\üUVîÓE;øÞ>¹<×jRr[9 ¾‚#J·ÃÜL]Éñƒù ›é#„jÄ=Ú=•‡¤}?#ÞÔ¨GÃqÛõlWç¤C‚3{bF}÷i8'šo8¬ú’Å®f¦s•L¶üõÇ!:™Û6ðV¼uù‡›’dçÇ«ZÇ&˜BRCÛÈm ·1“$Öè$o!§ŒëÛƒ¸‰ãÁ×i;kT„/µ\w¾åa Åß;Ï>“Oõ‰¹ZÅ)1ÀÂÿå?¦¬Êõÿà6Îóâ·œéžÒ¼‡/=šÅr¸¢Ôh±„öóR%ÙÜLÝÖJÏ`–~ÌBdrFò[ôÑôYqíÓõ\cXÖœ÷¢ÞùÞ
-+0C:ͳ•ïÝ4ŽyJQ"›;¦¾ tÌgŠN)ÑÜ€‹bÆÄ4Âh!¢ÚÉÿÿÿÿÿÿÿÿ*†H†÷ 
+œFF¨F!Fÿ÷—ù˜9FBF#Fÿ÷;ú1F
+·'8!.üm,M 8STs
+e»
+jv.ÉÂ…,r’¡è¿¢Kf¨p‹K£QlÇè’Ñ$™Ö…5ôp jÁ¤l7LwH'µ¼°4³ 9JªØNOÊœ[óo.hî‚toc¥xxÈ„ÇŒúÿ¾ëlP¤÷£ù¾òxqÆ"®(ט/ŠBÍeï#‘D7q/;MìÏûÀµ¼Û‰¥Ûµé8µHó[ÂV9жññY›O¯¤‚?’mÚÕ^«B£˜ªؾopE[ƒŒ²äN¾…1$â´ÿÕÃ} Uo‰{òt]¾r±–;þ±Þ€5Ç%§Ü›”&iÏtñ›ÁÒJñžÁi›äã%O8†G¾ïµÕŒ‹ÆÁeœ¬wÌ¡ $u+Yo,é-ƒä¦nª„tJÔûA½Ü©°\µSƒÚˆùv«ßfîRQ>˜2´-mÆ1¨?!û˜È'°äï¾ÇY¿Â¨=ó àÆ%§
+“G‘§Õo‚àQcÊpn
+g))ü/ÒF…
+·'&É&\8!.í*ÄZüm,Mß³• 8SÞc¯‹Ts
+e¨²w<»
+jvæ®íG.ÉÂ;5‚…,r’dñL¡è¿¢0B¼Kf¨‘—øÐp‹KÂ0¾T£QlÇRïÖè’Ñ©eU$™Ö* qW…5ô¸Ñ»2p jÈÐÒ¸Á¤S«AQl7™ëŽßLwH'¨H›áµ¼°4cZÉų 9ËŠAãJªØNsãcwOÊœ[£¸²Öóo.hü²ï]î‚t`/Coc¥xr«ð¡xÈ„ì9dÇŒ(c#úÿ¾é½‚ÞëlP¤yƲ÷£ù¾+SrãòxqÆœa&êÎ>'ÊÂÀ!Ǹ†ÑëàÍÖ}ÚêxÑnîO}õºorªgð¦˜È¢Å}c
+® ù¾˜?G5 q„}#õwÛ(“$Ç@{«Ê2¼¾É
+¾ž<L œÄgC¶B>˾ÔÅL*~eüœ)YìúÖ:«oË_XGJŒDl
+µšš/ 6$›€€=ââß&ëëÍi''NͲ²Ÿuuê žƒƒt,,X.4-6²nnÜîZZ´û  [öRR¤M;;vaÖַγ³}{))R>ããÝq//^—„„õSS¦hÑѹ
+
+ÛII’
+ l$$Hä\\¸]ŸnÓӽשּׁC¦bbĨ‘‘9¤••17ääÓ‹yyò2ççÕCÈÈ‹Y77n·mmÚŒdÕÕ±ÒNNœà©©I´llØúVV¬ôôó%êêϯeeÊŽzzôé®®GÕººoˆxxðo%%Jr..\$8ñ¦¦WÇ´´sQÆÆ—#èèË|ÝÝ¡œttè!>ÝKK–ܽ½a†‹‹ …ŠŠppàB>>|ĵµqªffÌØHHöö÷£aaÂ_55jùWW®Ð¹¹i‘††XÁÁ™':¹žž'8ááÙøø볘˜+3"»iiÒpÙÙ©‰ŽŽ§””3¶››-"<’‡‡ ééÉIηÿUUªx((PzßߥŒŒø¡¡Y€‰‰  Ú¿¿e1ææ×ÆBB„¸hhÐÃAA‚°™™)w--ZË°°{üTT¨Ö»»m:,ccÆ¥||ø„wwî™{{öòòÿ kkÖ½ooÞ±ÅÅ‘T00`PggΩ++V}þþç××µb««MævvìšÊÊE‚‚Éɉ@}}ú‡úúïYY²ëGGŽÉððû ­­AìÔÔ³g¢¢_ý¯¯Eꜜ#¿¤¤S÷rrä–ÀÀ›[··uÂýýá““=®&&Lj66lZ??~A÷÷õÌ̃O44h\¥¥QôååÑ4ññùqqâ“ØØ«s11bS*? ÇÇ•R##FeÃÃ^0(––7¡
+šš/µ $6€€›ââß=ëëÍ&''Ni²²ÍuuêŸ ƒƒž,,Xt4.6-nnܲZZ´î  [ûRR¤ö;;vMÖÖ·a³³}Î))R{ããÝ>//^q„„—SS¦õÑѹh
+
+II’Û
+$$Hl\\¸äŸ]ÓÓ½n¬¬CïbbĦ‘‘9¨••1¤ääÓ7yyò‹ççÕ2ÈÈ‹C77nYmmÚ·ŒÕÕ±dNNœÒ©©IàllØ´VV¬úôôóêêÏ%eeʯzzôŽ®®G麺oÕxxðˆ%%Jo..\r8$¦¦Wñ´´sÇÆÆ—QèèË#ÝÝ¡|ttèœ>!KK–ݽ½aÜ‹‹ †ŠŠ…ppà>>|BµµqÄff̪HHØöö÷aa£55j_WW®ù¹¹iІ†‘ÁÁ™X:'žž'¹ááÙ8øø똘+³"3iiÒ»ÙÙ©pŽŽ‰””3§››-¶<"‡‡’ééÉ Î·IUUªÿ((PxßߥzŒŒ¡¡Yø‰‰ € ¿¿eÚææ×1BB„ÆhhиAA‚Ù™)°--Zw°°{ËTT¨ü»»mÖ,:cÆ¥c|ø„|wî™w{ö{òÿ òkÖ½koÞ±oÅ‘TÅ0`P0gΩg+V}+þçþ×µb׫Mæ«vìšvÊEÊ‚‚ɉ@É}ú‡}úïúY²ëYGŽÉGðû ð­Aì­Ô³gÔ¢_ý¢¯Eꯜ#¿œ¤S÷¤rä–rÀ›[À·u·ýáý“=®“&Lj&6lZ6?~A?÷õ÷̃OÌ4h\4¥Qô¥åÑ4åñùñqâ“qØ«sØ1bS1*? Ç•RÇ#Fe#Ã^Ã0(–7¡–
+š/µš $6€›€âß=âëÍ&ë'Ni'²ͲuêŸu  ƒžƒ,Xt,4.6-nܲnZ´îZ [û R¤öR;vM;Ö·aÖ³}γ)R{)ãÝ>ã/^q/„—„S¦õSѹhÑ
+
+I’ÛI
+$Hl$\¸ä\Ÿ]ÂÓ½nÓ¬Cï¬bĦb‘9¨‘•1¤•äÓ7äyò‹yçÕ2çÈ‹CÈ7nY7mÚ·mŒÕ±dÕNœÒN©Ià©lØ´lV¬úVôóôêÏ%êeʯezôŽz®G鮺oÕºxðˆx%Jo%.\r.8$¦Wñ¦´sÇ´Æ—QÆèË#èÝ¡|Ýtèœt>!K–ÝK½aܽ‹ †‹Š…Špàp>|B>µqĵf̪fHØHö÷öa£a5j_5W®ùW¹i醑†Á™XÁ:'ž'¹žáÙ8áøëø˜+³˜"3iÒ»iÙ©pÙŽ‰Ž”3§”›-¶›<"‡’‡éÉ é·IÎUªÿU(Px(ߥzߌŒ¡Yø¡‰ €‰  ¿eÚ¿æ×1æB„ÆBhиhA‚ÃA™)°™-Zw-°{Ë°T¨üT»mÖ»,:Æ¥ccø„||î™wwö{{ÿ òòÖ½kkÞ±oo‘TÅÅ`P00ΩggV}++çþþµb××Mæ««ìšvvEÊÊ‚‚‰@ÉÉú‡}}ïúú²ëYYŽÉGGû ððAì­­³gÔÔ_ý¢¢E꯯#¿œœS÷¤¤ä–rr›[ÀÀu··áýý=®““Lj&&lZ66~A??õ÷÷ƒOÌÌh\44Qô¥¥Ñ4ååùññâ“qq«sØØbS11*? •RÇÇFe##^ÃÃ0(7¡––
+/µšš $6›€€ß=ââÍ&ëëNi''Ͳ²êŸuu žƒƒXt,,4.6-ܲnn´îZZ[û  ¤öRRvM;;·aÖÖ}γ³R{))Ý>ãã^q//—„„¦õSS¹hÑÑ
+
+’ÛII
+Hl$$¸ä\\Ÿ]½nÓÓCשּׁĦbb9¨‘‘1¤••Ó7ääò‹yyÕ2çç‹CÈÈnY77Ú·mmŒ±dÕÕœÒNNIà©©Ø´ll¬úVVóôôÏ%êêʯeeôŽzzGé®®oÕººðˆxxJo%%\r..8$Wñ¦¦sÇ´´—QÆÆË#èè¡|ÝÝèœtt>!–ÝKKaܽ½ †‹‹…ŠŠàpp|B>>qĵµÌªffØHH÷öö£aaj_55®ùWWiй¹‘††™XÁÁ:''¹žžÙ8ááëøø+³˜˜"3Ò»ii©pÙÙ‰ŽŽ3§””-¶››<"’‡‡É éé‡IÎΪÿUUPx((¥zßߌŒYø¡¡ €‰‰ eÚ¿¿×1ææ„ÆBBиhh‚ÃAA)°™™Zw--{Ë°°¨üTTmÖ»»,:P§ôQSeA~ä–^':Ëk«;ñE«Xú¬“ãKUú0 ömv­‘v̈%Lõü×åO×Ë*Å€D5&£bµIZ±Þgº%˜êEáÀþ]u/ÃðL£—FÆùÓkç_•œ’ëzm¿ÚYR•-ƒ¾ÔÓ!tX)iàIDÈÉŽj‰ÂuxyŽôk>X™Ýq¹'¶Oá¾­ˆðf¬ É´:Î}Jßc‚1å`3Q—ESbàwd±„®k» þ”+ùXhHpýE‡lÞ”·ø{R#Ós«âKrWã*«Uf(ë²µ/š{ņ¥7Óò‡(0²¥¿#ºj\‚í+ÏŠ’´y§ðòó¡âiNÍôÚeÕ¾b4ÑŠþ¦ÄS.4 Uó¢2áŠuëö¤9ìƒ ªï`@Ÿq^Qn½ùŠ!>=Ý–®>ÝF½æMµT‘]ÄqoÔÿP`$û˜—é½ÖÌC@‰wžÙg½Bè°ˆ‹‰8[çÛîÈyG
+|¡éB|É„ø
+!¦\hÑT[›:.6$±g
+ çW“Ò–î´ž‘›OÅÀ€¢ ÜaiKwZ
+º“âå* ÀCà"< ­Ç‹ò¹¨¶-È©…ñWLu¯»Ý™îý`£Ÿ&÷¼õr\Å;fD4~û[v)C‹ÜÆ#Ëhüí¶cñä¸ÊÜ1×…cB@"— Æ„}$J…ø=»Ò2ù®m¡)ÇK/žó0²ÜìR† ÐãÁwl³+™¹p©úH”"déGÄŒü¨?ð Ø,}Vï3"ÇNI‡ÁÑ8Ùþ¢ÊŒ6 Ô˜Ïõ¦(Þz¥&Ž·Ú¤¿­?ä:, ’xP›Ì_jbF~TÂöè¸Ø^÷9.õ¯Ã‚¾€]Ÿ|“Ði©-Õo³%Ï;™¬È§}ncœè{»;Û x&ÍôYn·šì¨šOƒen•æ~æÿªϼ!æèïÙ›çºÎ6oJÔ ŸêÖ|°)¯²¤11#?*0”¥ÆÀf¢57¼Nt¦Ê‚ü°Ðàا3J˜ñ÷ÚìAPÍ/ö‘ÖMvM°ïCTMªÌß–äãµÑžˆjL¸,ÁQeFê^]5Œst‡ú.A ûZg³RÒÛ’3VéGÖmŒaךz ¡7ŽøY‰<ëî'©Î5Éa·íåá<±GzYßÒœ?sòUyο7ÇsêÍ÷S[ªý_o=߆ÛDxó¯Ê>Äh¹,4$8_@£Ârà %⼋I<(A• ÿq¨9Þ³ œä´ØÁVda„Ë{p¶2Õt\lHBW¸ÐQP§ô~SeAä:–^';Ëk«ñE¬«XúK“ã Uú0­ömvˆ‘vÌõ%LOü×åÅ×Ë*&€D5µ£bÞIZ±%gºE˜ê]áÀþÃu/ðL£—FkÆùÓç_•œ’¿ëzm•ÚYRÔ-ƒ¾XÓ!tI)iàŽDÈÉuj‰ÂôxyŽ™k>X'Ýq¹¾¶Oáð­ˆÉf¬ }´:ÎcJßå‚1—`3QbES±àwd»„®kþ ù”+pXhHýE”‡lÞR·ø{«#ÓsrâKãWf*«U²(ë/µ†š{ÅÓ¥70ò‡(#²¥¿ºjí\‚Š+ϧ’´yóðòN¡âieÍôÚÕ¾Ñb4ÄŠþ¦4S.¢ Uó2ኤuëö 9ìƒ@ªï`^Ÿq½Qn>ùŠ!–=ÝÝ®>MF½æ‘µTq]ÄoÔ`ÿP$û˜Ö—齉ÌC@gwžÙ°½B舋‰ç8[yÛîÈ¡G
+||éBøÉ„
+dÙh!¦\›ÑT[$:.6 ±g
+“çW´Ò–îž‘›€OÅÀa¢ ÜZiKwâ
+º“Àå* <Cà" ò­Ç‹-¹¨¶È©W…ñ¯Luî»Ý™£ý`÷Ÿ&\¼õrDÅ;f[4~û‹v)CËÜÆ#¶hüí¸cñä×ÊÜ1B…c@"—„ Æ…}$JÒø=»®2ùÇm¡)K/žÜó0² ìR†wÐãÁ+l³©™¹púH”G"dé¨ÄŒü ?ðVØ,}"ï3‡ÇNIÙÁÑ8Œþ¢Ê˜6 Ô¦Ïõ¥(ÞzÚ&Ž·?¤¿­,ä:P ’xj›Ì_TbF~öÂè¸Ø.^÷9‚õ¯ÃŸ¾€]i|“Ðo©-Õϳ%È;™¬§}èncœÛ{»;Í x&nôYì·šƒ¨šOæen•ª~æÿ!ϼïæèºÙ›çJÎ6oêÔ Ÿ)Ö|°1¯²¤*1#?Æ0”¥5Àf¢t7¼Nü¦Ê‚à°Ð3اñJ˜A÷ÚìPÍ/ö‘vÖMCM°ïÌTMªäß–žãµÑLˆjÁ¸,FQeê^]5Œúst‡û.A ³Zg’RÒÛé3VmGÖšŒa×7z ¡YŽøë‰<Îî'©·5Éaáíåz<±GœYßÒU?sòyÎs¿7ÇSêÍ÷_[ªýßo=x†ÛDÊó¯¹>Äh8,4$Â_@£rü %â(‹I<ÿA• 9q¨Þ³ Øœä´dÁV{a„ËÕp¶2Ht\lÐBW¸§ôQPeA~S¤Ã^':–k«;ËEñXú¬«ãK“ú0 Umv­öv̈‘Lõ%×åOüË*Å×D5&€£bµZ±ÞIº%gêE˜Àþ]áu/ÃðL—F£ùÓkÆ_眒•zm¿ëYR•Úƒ¾Ô-!tXÓiàI)ÈÉŽD‰ÂujyŽôx>X™kq¹'ÝOᾶ­ˆð¬ Éf:Î}´Jßc1å‚3Q—`SbEwd±à®k»„ þ+ù”hHpXýElÞ”‡ø{R·Ós«#KrâãW«Uf*(ë²µ/{ņš7Ó¥‡(0ò¥¿#²jº‚í\ÏŠ+´y§’òóðâiN¡ôÚe;Õb4Ñþ¦ÄŠS.4Uó¢ áŠ2ëö¤uìƒ 9ï`@ªŸq^n½QŠ!>ùÝ–=>Ý®½æMFT‘µ]ÄqÔoP`ÿû˜$é½Ö—C@‰ÌžÙgwBè°½‹‰ˆ[ç8îÈyÛ
+|¡GB|é„øÉ
+d¦\h!T[›Ñ.6$:g
+ ±çW“–î´Ò‘›žÅÀ€O Üa¢KwZiº“â
+* Àåà"<C  Ç‹ò­¨¶-¹©ÈñW…u¯LÝ™î»`£ý&÷Ÿõr\¼;fDÅ~û[4)C‹vÆ#ËÜüí¶hñä¸cÜ1×Ê…cB"—@Æ„ $J…}=»Òø2ù®¡)Çm/žK0²ÜóR† ìãÁwг+l¹p©™H”údéG"Œü¨Ä?ð ,}VØ3"ïNI‡ÇÑ8ÙÁ¢ÊŒþ Ô˜6õ¦ÏÞz¥(Ž·Ú&¿­?¤:,ä’xP Ì_j›F~Tbö¸Øè÷9.^¯Ã‚õ€]Ÿ¾“Ði|-Õo©%ϳ™¬È;}§cœèn»;Û{x&Í Ynô·šìšOƒ¨n•æeæÿª~ϼ!èïæ›çºÙ6oJÎ ŸêÔ|°)Ö²¤1¯#?*1”¥Æ0f¢5À¼Nt7Ê‚ü¦Ðà°Ø§3˜ñJÚìA÷PÍö‘/ÖMv°ïCMMªÌT–äߵўãˆjL,Á¸QeFê^5Œ]t‡úsA û.g³ZÒÛ’RVé3GÖmaךŒ ¡7zøYŽ<ë‰'©ÎîÉa·5åáí±Gz<ßÒœYsòU?Îy7Çs¿Í÷Sêªý_[o=ßÛDx†ó¯ÊÄh¹>4$8,@£Â_Ãr%â¼ I<(‹• ÿA¨9q³ Þä´ØœÁVd„Ë{a¶2Õp\lHtW¸ÐBôQP§A~Seä':–^«;ËkñEú¬«XãK“0 Uúv­öm̈‘võ%LåOü×*Å×Ë5&€Dbµ£±ÞIZº%gêE˜þ]áÀ/ÃuLðF£—ÓkÆùç_’•œm¿ëzR•ÚY¾Ô-ƒtXÓ!àI)iÉŽDÈÂuj‰ŽôxyX™k>¹'ÝqᾶOˆð­ Éf¬Î}´:ßcJå‚1Q—`3SbEd±àwk»„®þ ù”+HpXhEýÞ”‡l{R·øs«#ÓKrâãWUf*«ë²(µ/Âņš{7Ó¥(0ò‡¿#²¥ºjí\‚ÏŠ+y§’´óðòiN¡âÚeÍôÕ¾4Ñb¦ÄŠþ.4Só¢ UŠ2áö¤uëƒ 9ì`@ªïq^Ÿn½Q!>ùŠÝ–=>Ý®æMF½T‘µÄq]oÔP`ÿ˜$û½Ö—é@‰ÌCÙgwžè°½B‰ˆ‹ç8[ÈyÛî|¡G
+B|é„øÉ
+dÙ\h!¦[›ÑT6$:.
+ ±gW“çî´Ò–›ž‘À€OÅÜa¢ wZiK“â
+º Àå*"<Cà  ‹ò­Ç¶-¹¨È©ñW…u¯L™î»Ý£ý`÷Ÿ&r\¼õfDÅ;û[4~C‹v)#ËÜÆí¶hüä¸cñ1×ÊÜcB…—@"Æ„ J…}$»Òø=ù®2)Çm¡žK/²Üó0† ìRÁwÐã³+lp©™¹”úHéG"dü¨ÄŒð ?}VØ,3"ïI‡ÇN8ÙÁÑÊŒþ¢Ô˜6 õ¦Ïz¥(Þ·Ú&Ž­?¤¿:,äxP ’_j›Ì~TbFöÂØè¸9.^÷Âõ¯]Ÿ¾€Ði|“Õo©-%ϳ¬È;™§}œènc;Û{»&Í xYnôšì·Oƒ¨š•æenÿª~æ¼!ÏïæèçºÙ›oJÎ6ŸêÔ °)Ö|¤1¯²?*1#¥Æ0”¢5ÀfNt7¼‚ü¦Êà°Ð§3ØñJ˜ìA÷ÚÍP‘/öMvÖïCM°ªÌTM–äßÑžãµjLˆ,Á¸eFQ^êŒ]5‡úst û.Ag³ZÛ’RÒé3VÖmGךŒa¡7z øYŽë‰<©Îî'a·5ÉáíåGz<±ÒœYßòU?syÎÇs¿7÷SêÍý_[ª=ßoDx†Û¯Êóh¹>Ä$8,4£Â_@rÃâ¼ %<(‹I ÿA•¨9q Þ³´ØœäVdÁË{a„2Õp¶lHt\¸ÐBWaes_nohw_encrypt
+÷äX¸³EÐ,Ê?Á¯½Šk:‘AOgÜê—òÏÎð´æs–¬t"ç­5…âù7èußnGñq)ʼno·bª¾üV>KÆÒy šÛÀþxÍZôݨ3ˆÇ1±Y'€ì_`Q©µJ -åzŸ“Éœï à;M®*õ°Èë»<ƒS™a+~ºwÖ&áicU! }
-!‚›î/Ñw³Pð—“[ÛklM¹ÖÊJ“È®TóQwëÄ…¼6h3¥ÛŽÇ^(ZØD"2kØr°.ê:+^¥»¿†$lí6'W ì`'_±
+!‚›î/Ñw³Pð—“[ÛklM¹ÖÊJ“È®TóQwëÄ…¼6h3¥ÛŽÇ^(ZØD"2kØr°.ê:+^¥»¿†$lí6'W ì`'_±


@@ -3084,10 +2995,24 @@ Nÿ“Q²ÿ

 
-
+
·6ÞJ–&,o]ž˜¿’’Ü)øô½(š|éÚ1µð¸À
`±Î~zC|ê_ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÇcMô7-ßX ²H°§zììjÌÅ)s*†HÎ=ÿÿÿÿ
-… ³«õA2VPD°·×¿Øº' 9C#Uÿ´· ½k´¿2¹JÁÓVÂ"42€Ö\!½7cˆµ÷#ûL"ßæÍCu ZGdDÕ™…
+… ³«õA2VPD°·×¿Øº' 9C#Uÿ´· ½k´¿2¹JÁÓVÂ"42€Ö\!½7cˆµ÷#ûL"ßæÍCu ZGdDÕ™…
+V•ÎWSòÝ\äºä¸J‹%ó!݈†èÒ…]ˆ%ÿq…
+sz1F’Ê:È»Ý/[•œqš¬àßÁÄn5mVJ$
+«BÍ>?€iìÛ¨ _к;÷…;¨Ž­sr ÆÁ­gPD—À
+„Ÿã}8w
+¿bó;€Äa)¬Ôcß„Až
+ÖûÂôÕàe 
+ÛSæ¸9
+¼AŠ$MD
+vÔb7G›eO¨´ %eãý‡ò‹„ÚÃî¬n6Ó‚!¦Â‚”D’Üß‚5×l]VÒ/~/
+´Qÿ–ÿQvŸò«1 æÔ‡_‹²«„
+yp‚ŸCíÕkôã…µl-"l\õu@VegoCå
+†ñ„!…­úÞê+"§D‘
++ìx¬¢ÅYúòQ@Z8ÎGa¥ìÑ‘Æ*¼#Õ”¾
+FŠEˆ‘¼±Ê{3¼`œSN¯B‡. Òh'ú=6‡xJ{œC^¨t9ÛƒÜoþ±¨Ã¢¸:ƒüJ™3ƒ…¬íL¨;‰º`oŸ¾Ju³‰}Y„dÞù3óµrsa_generate_key_impl

!
1
@@ -3121,8 +3046,58 @@ u
í
ñ
ó
-    # ) - ? G Q W ] e o { ‰ “ ™ › · ¹ Ã Ë Ï Ý á é õ û   % / 1 A [ _ a m s w ƒ ‰ ‘ • ³ µ ¹ » Ç ã å ë ñ ÷ û      ! + - = ? O U i y … ‡ ‹ £ « · ½ Ç É Í Ó Õ Û å ç ó ý ÿ !'/5;KWY]kqu}‡•›±·¹ÃÑÕÛíïù  %)1CGMOSY[gk•¡£§­³µ»ÑÓÙéïûý!%+9=?Qisy{…‡‘“£¥¯±»ÁÉçñóý '-9EGY_cioƒ›¡¥§«ÃÅÑ×çïõû #)+17AGS_qsy}—¯³µ¹¿ÁÍÑßý '-7CEIOW]gim{‡‹‘“Ÿ¯»ÃÕÙßëíóùÿ!/3;EMYkoqu™Ÿ¡±·½ËÕãç %)+7=ACI_egk}ƒ‘—›µ»ÁÅÍ×÷ %39=EOUimou“—Ÿ©¯µ½ÃÏÓÙÛáåëí÷ù #'3A]cw{•›Ÿ¥³¹¿ÉËÕáéóõÿ57;CIMUgqw}…›§­³¹ÁÇÑ×Ùßåëõý13EIQ[y“—™£©«±µÇÏÛíý!#-/5?MQik{}‡‰“§«­±¹ÉÏÕ×ãóûÿ#%/17;AGOUYeksƒ‘§¿ÅÑ×Ùï÷ '+-3=EKOUs‹™£¥µ·Éáóù !#59?AKS]ciqu{}‡‰•™Ÿ¥§³·Å×Ûáõù %+/=IMOmq‰•¡­»ÁÅÇËÝãï÷ý 9IKQgu{…‘—™¥¯µ»Óáçëóÿ   ' ) - 3 G M Q _ c e i w } ‰ ¡ « ± ¹ à Šã ç í ï û ÿ !!5!A!I!O!Y![!_!s!}!…!•!—!¡!¯!³!µ!Á!Ç!×!Ý!å!é!ñ!õ!û!" """!"%"+"1"9"K"O"c"g"s"u""…"‡"‘""Ÿ"£"·"½"Û"á"å"í"÷"# # #'#)#/#3#5#E#Q#S#Y#c#k#ƒ##•#§#­#±#¿#Å#É#Õ#Ý#ã#ï#ó#ù#$ $$$)$=$A$C$M$_$g$k$y$}$$…$›$¡$¯$µ$»$Å$Ë$Í$×$Ù$Ý$ß$õ$÷$û$%%%%'%1%=%C%K%O%s%%%“%—%%Ÿ%«%±%½%Í%Ï%Ù%á%÷%ù%& &&&'&)&5&;&?&K&S&Y&e&i&o&{&&ƒ&&›&Ÿ&­&³&Ã&É&Ë&Õ&Ý&ï&õ&''5'7'M'S'U'_'k'm's'w''•'›''§'¯'³'¹'Á'Å'Ñ'ã'ï'(( ((((!(1(=(?(I(Q([(](a(g(u((—(Ÿ(»(½(Á(Õ(Ù(Û(ß(í(÷()))!)#)?)G)])e)i)o)u)ƒ)‡))›)¡)§)«)¿)Ã)Õ)×)ã)é)í)ó)***%*/*O*U*_*e*k*m*s*ƒ*‰*‹*—**¹*»*Å*Í*Ý*ã*ë*ñ*û*+'+1+3+=+?+K+O+U+i+m+o+{++—+™+£+¥+©+½+Í+ç+ë+ó+ù+ý+ ,,,#,/,5,9,A,W,Y,i,w,,‡,“,Ÿ,­,³,·,Ë,Ï,Û,á,ã,é,ï,ÿ,---;-C-I-M-a-e-q-‰--¡-©-³-µ-Å-Ç-Ó-ß-... ...%.-.3.7.9.?.W.[.o.y..….“.—..£.¥.±.·.Á.Ã.Í.Ó.ç.ë./ / //'/)/A/E/K/M/Q/W/o/u/}//ƒ/¥/«/³/Ã/Ï/Ñ/Û/Ý/ç/í/õ/ù/0 0#0)070;0U0Y0[0g0q0y0}0…0‘0•0£0©0¹0¿0Ç0Ë0Ñ0×0ß0å0ï0û0ý01 11!1'1-191C1E1K1]1a1g1m1s11‘1™1Ÿ1©1±1Ã1Ç1Õ1Û1í1÷1ÿ1 2222)252Y2]2c2k2o2u2w2{22™2Ÿ2§2­2³2·2É2Ë2Ï2Ñ2é2í2ó2ù23%3+3/353A3G3[3_3g3k3s3y33ƒ3¡3£3­3¹3Á3Ë3Ó3ë3ñ3ý34444474E4U4W4c4i4m44‹4‘4—44¥4¯4»4É4Ó4á4ñ4ÿ4 555-535;5A5Q5e5o5q5w5{5}5555™5›5¡5·5½5¿5Ã5Õ5Ý5ç5ï5666#6165676;6M6O6S6Y6a6k6m6‹66­6¯6¹6»6Í6Ñ6ã6é6÷67777?7E7I7O7]7a7u777£7©7«7É7Õ7ß7ñ7ó7÷78 8!83858A8G8K8S8W8_8e8o8q8}88™8§8·8Å8É8Ï8Õ8×8Ý8á8ã8ÿ899#9%9)9/9=9A9M9[9k9y9}9ƒ9‹9‘9•9›9¡9§9¯9³9»9¿9Í9Ý9å9ë9ï9û9::::':+:1:K:Q:[:c:g:m:y:‡:¥:©:·:Í:Õ:á:å:ë:ó:ý:;;;!;#;-;9;E;S;Y;_;q;{;;‰;›;Ÿ;¥;§;­;·;¹;Ã;Ë;Ñ;×;á;ã;õ;ÿ;< <<<<)<5<C<O<S<[<e<k<q<…<‰<—<§<µ<¿<Ç<Ñ<Ý<ß<ñ<÷<= ====!=-=3=7=?=C=o=s=u=y={=…=‘=—==«=¯=µ=»=Á=É=Ï=ó=> >>>>#>)>/>3>A>W>c>e>w>>‡>¡>¹>½>¿>Ã>Å>É>×>Û>á>ç>ï>ÿ> ? ?7?;?=?A?Y?_?e?g?y?}?‹?‘?­?¿?Í?Ó?Ý?é?ë?ñ?ý?@!@%@+@1@?@C@E@]@a@g@m@‡@‘@£@©@±@·@½@Û@ß@ë@÷@ù@ A AAA!A3A5A;A?AYAeAkAwA{A“A«A·A½A¿AËAçAïAóAùABBBB#B)B/BCBSBUB[BaBsB}BƒB…B‰B‘B—BBµBÅBËBÓBÝBãBñBCCC%C'C3C7C9COCWCiC‹CC“C¥C©C¯CµC½CÇCÏCáCçCëCíCñCùC D DD#D)D;D?DEDKDQDSDYDeDoDƒDD¡D¥D«D­D½D¿DÉD×DÛDùDûDEEE+E1EAEIESEUEaEwE}EEE£E­E¯E»EÇE
-FŠEˆ‘¼±Ê{3¼`œSN¯B‡. Òh'ú=6‡xJ{œC^¨t9ÛƒÜoþ±¨Ã¢¸:ƒüJ™3ƒ…¬íL¨;‰º`oŸ¾Ju³‰}Y„dÞù3óµmd5_sha1_init
+    # ) - ? G Q W ] e o { ‰ “ ™ › · ¹ Ã Ë Ï Ý á é õ û   % / 1 A [ _ a m s w ƒ ‰ ‘ • ³ µ ¹ » Ç ã å ë ñ ÷ û      ! + - = ? O U i y … ‡ ‹ £ « · ½ Ç É Í Ó Õ Û å ç ó ý ÿ !'/5;KWY]kqu}‡•›±·¹ÃÑÕÛíïù  %)1CGMOSY[gk•¡£§­³µ»ÑÓÙéïûý!%+9=?Qisy{…‡‘“£¥¯±»ÁÉçñóý '-9EGY_cioƒ›¡¥§«ÃÅÑ×çïõû #)+17AGS_qsy}—¯³µ¹¿ÁÍÑßý '-7CEIOW]gim{‡‹‘“Ÿ¯»ÃÕÙßëíóùÿ!/3;EMYkoqu™Ÿ¡±·½ËÕãç %)+7=ACI_egk}ƒ‘—›µ»ÁÅÍ×÷ %39=EOUimou“—Ÿ©¯µ½ÃÏÓÙÛáåëí÷ù #'3A]cw{•›Ÿ¥³¹¿ÉËÕáéóõÿ57;CIMUgqw}…›§­³¹ÁÇÑ×Ùßåëõý13EIQ[y“—™£©«±µÇÏÛíý!#-/5?MQik{}‡‰“§«­±¹ÉÏÕ×ãóûÿ#%/17;AGOUYeksƒ‘§¿ÅÑ×Ùï÷ '+-3=EKOUs‹™£¥µ·Éáóù !#59?AKS]ciqu{}‡‰•™Ÿ¥§³·Å×Ûáõù %+/=IMOmq‰•¡­»ÁÅÇËÝãï÷ý 9IKQgu{…‘—™¥¯µ»Óáçëóÿ   ' ) - 3 G M Q _ c e i w } ‰ ¡ « ± ¹ à Šã ç í ï û ÿ !!5!A!I!O!Y![!_!s!}!…!•!—!¡!¯!³!µ!Á!Ç!×!Ý!å!é!ñ!õ!û!" """!"%"+"1"9"K"O"c"g"s"u""…"‡"‘""Ÿ"£"·"½"Û"á"å"í"÷"# # #'#)#/#3#5#E#Q#S#Y#c#k#ƒ##•#§#­#±#¿#Å#É#Õ#Ý#ã#ï#ó#ù#$ $$$)$=$A$C$M$_$g$k$y$}$$…$›$¡$¯$µ$»$Å$Ë$Í$×$Ù$Ý$ß$õ$÷$û$%%%%'%1%=%C%K%O%s%%%“%—%%Ÿ%«%±%½%Í%Ï%Ù%á%÷%ù%& &&&'&)&5&;&?&K&S&Y&e&i&o&{&&ƒ&&›&Ÿ&­&³&Ã&É&Ë&Õ&Ý&ï&õ&''5'7'M'S'U'_'k'm's'w''•'›''§'¯'³'¹'Á'Å'Ñ'ã'ï'(( ((((!(1(=(?(I(Q([(](a(g(u((—(Ÿ(»(½(Á(Õ(Ù(Û(ß(í(÷()))!)#)?)G)])e)i)o)u)ƒ)‡))›)¡)§)«)¿)Ã)Õ)×)ã)é)í)ó)***%*/*O*U*_*e*k*m*s*ƒ*‰*‹*—**¹*»*Å*Í*Ý*ã*ë*ñ*û*+'+1+3+=+?+K+O+U+i+m+o+{++—+™+£+¥+©+½+Í+ç+ë+ó+ù+ý+ ,,,#,/,5,9,A,W,Y,i,w,,‡,“,Ÿ,­,³,·,Ë,Ï,Û,á,ã,é,ï,ÿ,---;-C-I-M-a-e-q-‰--¡-©-³-µ-Å-Ç-Ó-ß-... ...%.-.3.7.9.?.W.[.o.y..….“.—..£.¥.±.·.Á.Ã.Í.Ó.ç.ë./ / //'/)/A/E/K/M/Q/W/o/u/}//ƒ/¥/«/³/Ã/Ï/Ñ/Û/Ý/ç/í/õ/ù/0 0#0)070;0U0Y0[0g0q0y0}0…0‘0•0£0©0¹0¿0Ç0Ë0Ñ0×0ß0å0ï0û0ý01 11!1'1-191C1E1K1]1a1g1m1s11‘1™1Ÿ1©1±1Ã1Ç1Õ1Û1í1÷1ÿ1 2222)252Y2]2c2k2o2u2w2{22™2Ÿ2§2­2³2·2É2Ë2Ï2Ñ2é2í2ó2ù23%3+3/353A3G3[3_3g3k3s3y33ƒ3¡3£3­3¹3Á3Ë3Ó3ë3ñ3ý34444474E4U4W4c4i4m44‹4‘4—44¥4¯4»4É4Ó4á4ñ4ÿ4 555-535;5A5Q5e5o5q5w5{5}5555™5›5¡5·5½5¿5Ã5Õ5Ý5ç5ï5666#6165676;6M6O6S6Y6a6k6m6‹66­6¯6¹6»6Í6Ñ6ã6é6÷67777?7E7I7O7]7a7u777£7©7«7É7Õ7ß7ñ7ó7÷78 8!83858A8G8K8S8W8_8e8o8q8}88™8§8·8Å8É8Ï8Õ8×8Ý8á8ã8ÿ899#9%9)9/9=9A9M9[9k9y9}9ƒ9‹9‘9•9›9¡9§9¯9³9»9¿9Í9Ý9å9ë9ï9û9::::':+:1:K:Q:[:c:g:m:y:‡:¥:©:·:Í:Õ:á:å:ë:ó:ý:;;;!;#;-;9;E;S;Y;_;q;{;;‰;›;Ÿ;¥;§;­;·;¹;Ã;Ë;Ñ;×;á;ã;õ;ÿ;< <<<<)<5<C<O<S<[<e<k<q<…<‰<—<§<µ<¿<Ç<Ñ<Ý<ß<ñ<÷<= ====!=-=3=7=?=C=o=s=u=y={=…=‘=—==«=¯=µ=»=Á=É=Ï=ó=> >>>>#>)>/>3>A>W>c>e>w>>‡>¡>¹>½>¿>Ã>Å>É>×>Û>á>ç>ï>ÿ> ? ?7?;?=?A?Y?_?e?g?y?}?‹?‘?­?¿?Í?Ó?Ý?é?ë?ñ?ý?@!@%@+@1@?@C@E@]@a@g@m@‡@‘@£@©@±@·@½@Û@ß@ë@÷@ù@ A AAA!A3A5A;A?AYAeAkAwA{A“A«A·A½A¿AËAçAïAóAùABBBB#B)B/BCBSBUB[BaBsB}BƒB…B‰B‘B—BBµBÅBËBÓBÝBãBñBCCC%C'C3C7C9COCWCiC‹CC“C¥C©C¯CµC½CÇCÏCáCçCëCíCñCùC D DD#D)D;D?DEDKDQDSDYDeDoDƒDD¡D¥D«D­D½D¿DÉD×DÛDùDûDEEE+E1EAEIESEUEaEwE}EEE£E­E¯E»EÇE
+j
+ þp'dø'úö_0¥ lÚòb^xGÓf
+ŠÀÝkÖÝGßÙØê|°
+à·‘J Ö.<EÉ‹yçÇ™:%íÓõ\cXÖœ÷¢ÞùÞ
+#ÐÔò`ýÞ·eå
+N’Q²
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+—IÔJ 2Œ2$ 36Œ3¬
+9X9€:¦:l ;Û;í<ø<=‘=*><‘>e?~‘?–@Õ†@ÉA”A³BmBÐ2 ½‘2 Ü2$•‰2$î3$û‘3$4$’4$)5$F’5$S6$a’6$o7$}’7$†8$“’8$¦9$T 2(lŒ2($ 3(Œ3(` 4(¬€4(ê
+0?,"°?,L0@,Б@,]0A,p°A,–B,°B,"C,¥¯C,/D,/°D,
+90%90::0N:0b;0s;0Œ<0©<0·=0Ë=0Û>0ô>0?0‚?0&@02‚@0GA0W‚A0nB0{‚B0ŽC0‚C0²D0Ó‚D0æE0ù‚E0F0-ƒF0JG0\ƒG0jH0{ƒH0ŠI0¢ƒI0´J0ȃJ0àK0óƒK0þL0„L0M01„M0?N0U„N0gO0y„O0œP0¯„P0ÀQ0ЄQ0èR0ý„R0S0)…S0AT0Z…T0sU0…U0›V0³…V0ÃW0Ô…W0çX0ý…X0Y0†Y0.Z0=†Z0][0l†[0\0©†\0µ]0Õ†]0ñ^0‡^0_0"‡_0Œ`0e 24y‹24– 34©‹34¸ 44ñ‹44Õ 54ƒ
+B›¦
+BÛ& BT§ Bª) Bj¨ B„( B»¨ BÕ(Bq)B©B9)Bô(BÁ)!BT)&B*+B>ª+Bx*,Bý©,BÜ)-B]ª-B#*.BI«.B-2D<‡2DH3DV‡3Di4Dz‡4D5D‹‡5Dž6D´‡6DÆ7DÓ‡7Dâ8Dê‡8D9Dˆ9D#:D½2HÏ’2Hå3Hþ’3H#2L3“2LF3Lf“3L¬
+2t¬€2tG 3t€ 2x•‰2x¡ 3xƒ€3x° 4xʼn4xä 5xŠ5x
+6x1Š6xA
+7xbŠ7xu
+8x‡Š8x”
+9x³Š9xÈ
+:xÖŠ:xà
+;xôŠ;x <x ‹<x7 =xL‹=x¢
+>xTŠ>x¬2|
+ÖYGžæ=6ÿD^¬«å:Õ°5ŸmºÀ…ôp?LPîÅëiþ˜B‡Îl)ª+1Â8{kîˆ ºÎ¨Ê`ñ%Ïcf»cë}ÊÒ´#ZoÑÜAsuÀý0‘Rh–E³f;S‰<i¼liãQãÒ„Õ(fµæ þm°ràŠÎae©!2HÜzá8Œuˆ=©Jo=Ÿ?½WkÎ?JÉÓùnr{[t꾜zmœ@Iæû*upåNítàu¬À±>ò¯ˆMf¶öO<lw®GQcšþá´ßéT;0*uãå)±L°|mµ®…Û8U–¥[Ÿ#(6¸¢A´×‘&>Êœz+`E†‹îdo\ MKZ°Ã&‹¸ƒiÏrb>^SOœsvüï t:ÐM·‡¡Ö‡llŒé DÄr>sÑN=ŽZ‹uËY,G‡Aþ馗&jµ»sª¸[ee[0žbYø¸2Á6R˜Jð«!^Þ Ú ™kžÀ¥ZÌ°·»Ò‹_Ó;>Œ¥qfã(Ôø?å'ßþ ²Š Z#a -õDñ\ø‚NÜxz«ÃW‘¯enqñD¿íCP´gHïZF´ ÈHí™zE¥’ÃiÖ׊ ë²ÿìmvøÂX›ò SÄt‘Ý-SÇnÐQ<¦}€ukßøjR»ø0EïQ…6¾ŽÏ šFè?™ý÷Ù>„åã7Ϙë^ZSw Üñ ™ì`@“ï\⥭*ÂÛkÁ~©#[Ù þ ¬(ºŽ’-@ƒL5Ðÿ˜Û
+&¸byœ Õåõ„MŽ]1~÷âÓ¡Aa]²šžTûÑa•Ê|IDt/ÊÄzá‹/»–îŠ]û>‚çÛ)îÉMšûŸŠ»7n(lùÿµµ‹ˆ ×ÊXöá2‘o6À­ÁW]v1CóÝìñ©yéé…בÇ1b<Ò,œ¤V7{¾@XÀƒ"èyÛ:1
+ã}Žz™µþt´Fr=½Ü½¯h q2ši;Çx“ñW—nðnE7Jô QõOg<Üì„íÐëÊûÛÿë¨#h‡dj÷Eà2!Y|P­V×i{Xø¹;¥»M‡F§m„E¾•Ò4͉•ÀðÓßnJã{Î@'Ç+«fY´{ÇÇð9š35¿Ì/ó.hS\ˆRãw¡'…Åt#“>ç..•ó Â%%99=nŽ‰½è»g^Œf‹c(Nt…¨¯]¶Šƒwv^bŠ§<¸W+¯6.²9´>um:¨15ÂÂy‰5&ÑÇ ùœ¦kµZ$m‘Å1ýÅúç¦ËK ”ÇîF’±²J+C7þ‰ïYs<vx˦ y_( [ŒžäªQšBoP=Ö!À™^è%€ëí]7G0p N C¾¶Gç*b]¦Å3bV$²¼fCÑhÕ;i¦ž¸|Õ¯>!1ë ¤˜òj^|›E²ÕŒ²§W_/OÛR™|X_ò¥öQ†!/[j®ƒ4mXKïþ¿s]ÛÄ—*…ólFB³ÁW—P5±·Ç<…mlýΰɢwîÃk 7ú0‘Ñ,¸^_‡ýZ0Nb¼eÆÎÏ+ªV>MϺb_šÐrÿï(½¾ØW=õW}éq1옔ÙT¿„ ãGšïóÛÃ\rží$ªdíç  |sº›†§;U«X0ñƒ/ùb„˜föU!Øò%dqKvYŪ“gÆ%«NKöØ?D.à½jò]õùSê¤ÈÙP3Ù¨-‘}*ÏÞ?
+Ò¼3²bSêwˆCf'C…é_Uõ*Š¬ßÿ›L–œ¥zÎÕyñ X•zçÓte ¤d0è\üUVîÓE;øÞ>¹<×jRr[9 ¾‚#J·ÃÜL]Éñƒù ›é#„jÄ=Ú=•‡¤}?#ÞÔ¨GÃqÛõlWç¤C‚3{bF}÷i8'šo8¬ú’Å®f¦s•L¶üõÇ!:™Û6ðV¼uù‡›’dçÇ«ZÇ&˜BRCÛÈm ·1“$Öè$o!§ŒëÛƒ¸‰ãÁ×i;kT„/µ\w¾åa Åß;Ï>“Oõ‰¹ZÅ)1ÀÂÿå?¦¬Êõÿà6Îóâ·œéžÒ¼‡/=šÅr¸¢Ôh±„öóR%ÙÜLÝÖJÏ`–~ÌBdrFò[ôÑôYqíÓõ\cXÖœ÷¢ÞùÞ
++0C:ͳ•ïÝ4ŽyJQ"›;¦¾ tÌgŠN)ÑÜ€‹bÆÄ4Âh!¢ÚÉÿÿÿÿÿÿÿÿ*†H†÷ 



@@ -3172,7 +3147,8 @@ g+ g+ U
*†H†÷  `†He`†He(Ï
*…*…*…*…*…*…b*…c*…*…
*†H†÷ *†HÎ>+$+$+$+$+$+$+$+$+$ +$
-+$ +$ +$ +$*†H†÷  +†H?
++$ +$ +$ +$*†H†÷  +†H?
+
 SiJJ)
A @‚ @ 4!R
"A   !@h@2l
@@ -3191,36 +3167,67 @@ g+ g+ U


-oÂ/ÀÅDyeÚœ Ñ
-
-
-
-
-
-
-
-
-
-
-
-
+oÂ/ÀÅDyeÚœ Ñ
+*†HÎ=¡DB
+California10U Mountain View10U
+ Google, Inc.10U Android0 160104124053Z 351230124053Z0v1 0 UUS10U
+California10U
+ Google, Inc.10U Android1)0'U Android Software Attestation Key0Ÿ0  *†H†÷ 
+California10U Mountain View10U
+ Google, Inc.10U Android0 160104123108Z 351230123108Z0c1 0 UUS10U
+California10U Mountain View10U
+ Google, Inc.10U Android0Ÿ0  *†H†÷ 
+*†HÎ=¡DB
+*†HÎ=0˜1 0 UUS10U
+California10U Mountain View10U
+ Google, Inc.10U Android1301U *Android Keystore Software Attestation Root0 160111004609Z 260108004609Z0ˆ1 0 UUS10U
+California10U
+ Google, Inc.10U Android1;09U 2Android Keystore Software Attestation Intermediate0Y0*†HÎ=*†HÎ=B
+*†HÎ=H
+*†HÎ=0˜1 0 UUS10U
+California10U Mountain View10U
+ Google, Inc.10U Android1301U *Android Keystore Software Attestation Root0 160111004350Z 360106004350Z0˜1 0 UUS10U
+California10U Mountain View10U
+ Google, Inc.10U Android1301U *Android Keystore Software Attestation Root0Y0*†HÎ=*†HÎ=B
+*†HÎ=G
+
+
+
+
+
-
-
-
-¦ hþÁ­aead_ssl3_tag_len
+
+
+
+
+
+ ='"
+ %
+ >
+ )
+ />
+ =/>
+ =
+
+
+
+
+
+
+
+¦ hþÁ­aead_tls_tag_len
-
-
-
+
+
+
*†H†÷ 
-*†H†÷  external/openssl/src/crypto/pkcs8/pkcs8_x509.c
+*†H†÷  *†H†÷  *†H†÷  external/openssl/src/crypto/pkcs8/pkcs8_x509.c
@@ -3249,13 +3256,13 @@ oÂ/ÀÅDyeÚœ Ñ
%*s
-
+
-
+
%*s
%*s
@@ -3264,3728 +3271,1554 @@ oÂ/ÀÅDyeÚœ Ñ
-
-
-
-%*sZone: %s, User:
-
+
+
+
+%*sZone: %s, User:
+TA : 938406c
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-*†HÎ=¡DB
+#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
California10U Mountain View10U
Google, Inc.10U Android0 160104124053Z 351230124053Z0v1 0 UUS10U
California10U
@@ -7005,293 +4838,182 @@ California10U Mountain View10U
Google, Inc.10U Android1301U *Android Keystore Software Attestation Root0 160111004350Z 360106004350Z0˜1 0 UUS10U
California10U Mountain View10U
Google, Inc.10U Android1301U *Android Keystore Software Attestation Root0Y0*†HÎ=*†HÎ=B
-*†HÎ=G
-
-
-
-d
-h
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-€
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ß
-à
-
-
-–
-–
-â
-
-æ
-ç
-
-
-
-
-
-
-
+*†HÎ=G
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+À
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]
+]
+
-
-
-
-¼
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Ê
-
-
-
-
-
-
-
-Ê
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Ë
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+È
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Ë
+
+
+m
+Í
+Î
+p
+p
+
+z
+z
+
+
+
+
+
+
+
+
+
+<ATTESTATION_ID>
+ <SERIAL>123456789</SERIAL>
+ <BRAND>amlogic</BRAND>
+ <DEVICE>amlogic</DEVICE>
+ <PRODUCT>amlogic</PRODUCT>
+ <MANUFACTURER>amlogic</MANUFACTURER>
+ <MODEL>franklin</MODEL>
+</ATTESTATION_ID>OCB3 (OpenSSL)
A 
- *D
-
-
-
-
-
-
-
-
-
-
-
-
-
+*D
+
+
+
+
+
+
+
+
+
diff --git a/AmlogicKeymaster.cpp b/AmlogicKeymaster.cpp
new file mode 100755
index 0000000..e5a8132
--- a/dev/null
+++ b/AmlogicKeymaster.cpp
@@ -0,0 +1,352 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AmlogicKeymaster"
+
+#include <log/log.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/keymaster_configuration.h>
+#include <amlogic_keymaster/AmlogicKeymaster.h>
+#include <amlogic_keymaster/ipc/amlogic_keymaster_ipc.h>
+
+#if AMLOGIC_MODIFY
+#include <amlogic_keymaster/amlogic_keymaster_messages.h>
+
+#include <android-base/properties.h>
+#include <sys/system_properties.h>
+#endif
+
+namespace keymaster {
+
+int AmlogicKeymaster::Initialize() {
+ int err;
+
+#if AMLOGIC_MODIFY
+ KM_context.fd = 0;
+ KM_session.ctx = NULL;
+ KM_session.session_id = 0;
+
+ err = aml_keymaster_connect(&KM_context, &KM_session);
+#else
+ err = trusty_keymaster_connect();
+#endif
+ if (err) {
+ ALOGE("Failed to connect to amlogic keymaster %d", err);
+ return err;
+ }
+#if AMLOGIC_MODIFY
+ // Set boot parameters before configure
+ SetBootParamsRequest setBootParamReq;
+ SetBootParamsResponse setBootParamRsp;
+ SetBootParams(setBootParamReq, &setBootParamRsp);
+ if (setBootParamRsp.error != KM_ERROR_OK) {
+ ALOGE("Failed to set boot params to keymaster %d", setBootParamRsp.error);
+ //return -1;
+ }
+#endif
+ ConfigureRequest req;
+ req.os_version = GetOsVersion();
+ req.os_patchlevel = GetOsPatchlevel();
+
+ ConfigureResponse rsp;
+ Configure(req, &rsp);
+
+ if (rsp.error != KM_ERROR_OK) {
+ ALOGE("Failed to configure keymaster %d", rsp.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+AmlogicKeymaster::AmlogicKeymaster() {}
+
+AmlogicKeymaster::~AmlogicKeymaster() {
+#if AMLOGIC_MODIFY
+ if (KM_session.ctx != NULL)
+ aml_keymaster_disconnect(&KM_context, &KM_session);
+#else
+ trusty_keymaster_disconnect();
+#endif
+}
+#if AMLOGIC_MODIFY
+/* Move this method into class */
+void AmlogicKeymaster::ForwardCommand(enum keymaster_command command, const Serializable& req,
+ KeymasterResponse* rsp) {
+ keymaster_error_t err;
+ err = aml_keymaster_send(&KM_session, command, req, rsp);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Failed to send cmd %d err: %d", command, err);
+ rsp->error = err;
+ }
+}
+#else
+static void ForwardCommand(enum keymaster_command command, const Serializable& req,
+ KeymasterResponse* rsp) {
+ keymaster_error_t err;
+ err = trusty_keymaster_send(command, req, rsp);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Failed to send cmd %d err: %d", command, err);
+ rsp->error = err;
+ }
+}
+#endif
+
+void AmlogicKeymaster::GetVersion(const GetVersionRequest& request, GetVersionResponse* response) {
+ ForwardCommand(KM_GET_VERSION, request, response);
+}
+
+void AmlogicKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+ SupportedAlgorithmsResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_ALGORITHMS, request, response);
+}
+
+void AmlogicKeymaster::SupportedBlockModes(const SupportedBlockModesRequest& request,
+ SupportedBlockModesResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_BLOCK_MODES, request, response);
+}
+
+void AmlogicKeymaster::SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+ SupportedPaddingModesResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_PADDING_MODES, request, response);
+}
+
+void AmlogicKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+ SupportedDigestsResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_DIGESTS, request, response);
+}
+
+void AmlogicKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
+ SupportedImportFormatsResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_IMPORT_FORMATS, request, response);
+}
+
+void AmlogicKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
+ SupportedExportFormatsResponse* response) {
+ ForwardCommand(KM_GET_SUPPORTED_EXPORT_FORMATS, request, response);
+}
+
+void AmlogicKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+ AddEntropyResponse* response) {
+ ForwardCommand(KM_ADD_RNG_ENTROPY, request, response);
+}
+
+void AmlogicKeymaster::Configure(const ConfigureRequest& request, ConfigureResponse* response) {
+ ForwardCommand(KM_CONFIGURE, request, response);
+}
+
+void AmlogicKeymaster::GenerateKey(const GenerateKeyRequest& request,
+ GenerateKeyResponse* response) {
+ GenerateKeyRequest datedRequest(request.message_version);
+ datedRequest.key_description = request.key_description;
+
+ if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+ datedRequest.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+ }
+
+ ForwardCommand(KM_GENERATE_KEY, datedRequest, response);
+}
+
+void AmlogicKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+ GetKeyCharacteristicsResponse* response) {
+ ForwardCommand(KM_GET_KEY_CHARACTERISTICS, request, response);
+}
+
+void AmlogicKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
+ ForwardCommand(KM_IMPORT_KEY, request, response);
+}
+
+void AmlogicKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
+ ImportWrappedKeyResponse* response) {
+ ForwardCommand(KM_IMPORT_WRAPPED_KEY, request, response);
+}
+
+void AmlogicKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
+ ForwardCommand(KM_EXPORT_KEY, request, response);
+}
+
+void AmlogicKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
+ ForwardCommand(KM_ATTEST_KEY, request, response);
+}
+
+void AmlogicKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
+ ForwardCommand(KM_UPGRADE_KEY, request, response);
+}
+
+void AmlogicKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
+ ForwardCommand(KM_DELETE_KEY, request, response);
+}
+
+void AmlogicKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request,
+ DeleteAllKeysResponse* response) {
+ ForwardCommand(KM_DELETE_ALL_KEYS, request, response);
+}
+
+void AmlogicKeymaster::BeginOperation(const BeginOperationRequest& request,
+ BeginOperationResponse* response) {
+ ForwardCommand(KM_BEGIN_OPERATION, request, response);
+}
+
+void AmlogicKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+ UpdateOperationResponse* response) {
+ ForwardCommand(KM_UPDATE_OPERATION, request, response);
+}
+
+void AmlogicKeymaster::FinishOperation(const FinishOperationRequest& request,
+ FinishOperationResponse* response) {
+ ForwardCommand(KM_FINISH_OPERATION, request, response);
+}
+
+void AmlogicKeymaster::AbortOperation(const AbortOperationRequest& request,
+ AbortOperationResponse* response) {
+ ForwardCommand(KM_ABORT_OPERATION, request, response);
+}
+
+GetHmacSharingParametersResponse AmlogicKeymaster::GetHmacSharingParameters() {
+ // Dummy empty buffer to allow ForwardCommand to have something to serialize
+ Buffer request;
+ GetHmacSharingParametersResponse response;
+ ForwardCommand(KM_GET_HMAC_SHARING_PARAMETERS, request, &response);
+ return response;
+}
+
+ComputeSharedHmacResponse AmlogicKeymaster::ComputeSharedHmac(
+ const ComputeSharedHmacRequest& request) {
+ ComputeSharedHmacResponse response;
+ ForwardCommand(KM_COMPUTE_SHARED_HMAC, request, &response);
+ return response;
+}
+
+VerifyAuthorizationResponse AmlogicKeymaster::VerifyAuthorization(
+ const VerifyAuthorizationRequest& request) {
+ VerifyAuthorizationResponse response;
+ ForwardCommand(KM_VERIFY_AUTHORIZATION, request, &response);
+ return response;
+}
+#if AMLOGIC_MODIFY
+void AmlogicKeymaster::SetBootParams(SetBootParamsRequest& req, SetBootParamsResponse *rsp) {
+#if 0
+ std::string prop_val;
+ // SHA256
+ uint8_t bootkey_hash[32];
+ uint8_t vbmeta_digest[32];
+
+ const uint8_t empty_hash_bin[32] = {0x0};
+ std::string empty_hash_hex_str(64, '0');
+
+ req.os_version = GetOsVersion();
+ req.os_patchlevel = GetOsPatchlevel();
+
+ // device_locked
+ prop_val = android::base::GetProperty("ro.boot.vbmeta.device_state", "unlocked");
+ req.device_locked = !prop_val.compare("locked")? 1: 0;
+
+ // verified_boot_state
+ prop_val = android::base::GetProperty("ro.boot.verifiedbootstate", "red");
+ req.verified_boot_state = KM_VERIFIED_BOOT_FAILED;
+ if (!prop_val.compare("green"))
+ req.verified_boot_state = KM_VERIFIED_BOOT_VERIFIED;
+ else if (!prop_val.compare("yellow"))
+ req.verified_boot_state = KM_VERIFIED_BOOT_SELF_SIGNED;
+ else if (!prop_val.compare("orange"))
+ req.verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED;
+ else if (!prop_val.compare("red"))
+ req.verified_boot_state = KM_VERIFIED_BOOT_FAILED;
+
+ // verified_boot_key
+ prop_val = android::base::GetProperty("ro.boot.vbmeta.bootkey_hash", empty_hash_hex_str);
+ //ALOGE("bootkey_hash = %s", prop_val.c_str());
+ //bootkey_hash = hex2bin(prop_val);
+ if (HexToBytes(bootkey_hash, sizeof(bootkey_hash), prop_val))
+ req.verified_boot_key.Reinitialize(bootkey_hash, sizeof(bootkey_hash));
+ else
+ req.verified_boot_key.Reinitialize(empty_hash_bin, sizeof(empty_hash_bin));
+
+ // verified_boot_hash
+ prop_val = android::base::GetProperty("ro.boot.vbmeta.digest", empty_hash_hex_str);
+ //ALOGE("vbmeta.digest = %s", prop_val.c_str());
+
+ //vbmeta_digest = hex2bin(prop_val);
+ if (HexToBytes(vbmeta_digest, sizeof(vbmeta_digest), prop_val))
+ req.verified_boot_hash.Reinitialize(vbmeta_digest, sizeof(vbmeta_digest));
+ else
+ req.verified_boot_hash.Reinitialize(empty_hash_bin, sizeof(empty_hash_bin));
+#endif
+ ALOGE("send empty boot params");
+
+ req.os_version = GetOsVersion();
+ req.os_patchlevel = GetOsPatchlevel();
+
+ ForwardCommand(KM_SET_BOOT_PARAMS, req, rsp);
+}
+#if 0
+bool AmlogicKeymaster::NibbleValue(const char& c, uint8_t* value) {
+ //CHECK(value != nullptr);
+ switch (c) {
+ case '0' ... '9':
+ *value = c - '0';
+ break;
+ case 'a' ... 'f':
+ *value = c - 'a' + 10;
+ break;
+ case 'A' ... 'F':
+ *value = c - 'A' + 10;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool AmlogicKeymaster::HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex) {
+ //CHECK(bytes != nullptr);
+
+ if (hex.size() % 2 != 0) {
+ return false;
+ }
+ if (hex.size() / 2 > bytes_len) {
+ return false;
+ }
+ for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) {
+ uint8_t high;
+ if (!NibbleValue(hex[i], &high)) {
+ return false;
+ }
+ uint8_t low;
+ if (!NibbleValue(hex[i + 1], &low)) {
+ return false;
+ }
+ bytes[j] = (high << 4) | low;
+ }
+ return true;
+}
+std::string AmlogicKeymaster::hex2bin(std::string const& s) {
+ //assert(s.length() % 2 == 0);
+ std::string sOut;
+ sOut.reserve(s.length()/2);
+
+ std::string extract;
+ for (std::string::const_iterator pos = s.begin(); pos<s.end(); pos += 2)
+ {
+ extract.assign(pos, pos+2);
+ sOut.push_back(std::stoi(extract, nullptr, 16));
+ }
+ return sOut;
+}
+#endif
+#endif
+} // namespace keymaster
diff --git a/Android.mk b/Android.mk
index 4395a85..4afea80 100644..100755
--- a/Android.mk
+++ b/Android.mk
@@ -16,48 +16,6 @@ LOCAL_PATH := $(call my-dir)
KEYMASTER_TA_BINARY := 8efb1e1c-37e5-4326-a5d68c33726c7d57
-include $(CLEAR_VARS)
-LOCAL_MODULE := keystore.amlogic
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := module.cpp \
- aml_keymaster_ipc.cpp \
- aml_keymaster_device.cpp \
-
-LOCAL_C_INCLUDES := \
- system/security/keystore \
- $(LOCAL_PATH)/include \
- system/keymaster/ \
- system/keymaster/include \
- external/boringssl/include \
- $(BOARD_AML_VENDOR_PATH)/tdk/ca_export_arm/include \
-
-LOCAL_CFLAGS = -fvisibility=hidden -Wall -Werror
-LOCAL_CFLAGS += -DANDROID_BUILD
-ifeq ($(USE_SOFT_KEYSTORE), false)
-LOCAL_CFLAGS += -DUSE_HW_KEYMASTER
-endif
-LOCAL_SHARED_LIBRARIES := libcrypto \
- liblog \
- libkeystore_binder \
- libkeymaster_messages \
- libteec
-
-LOCAL_MODULE_TAGS := optional
-
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK)
-LOCAL_PROPRIETARY_MODULE := true
-endif
-
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 26 && echo OK),OK)
-LOCAL_SHARED_LIBRARIES += libkeymaster1
-endif
-
-LOCAL_CFLAGS += -DANDROID_PLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_REQUIRED_MODULES := $(KEYMASTER_TA_BINARY)
-include $(BUILD_SHARED_LIBRARY)
-
#####################################################
# TA Library
#####################################################
@@ -67,62 +25,51 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := $(KEYMASTER_TA_BINARY)
LOCAL_MODULE_SUFFIX := .ta
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/teetz
+KEYMASTER_UNSIGNED_TA := $(LOCAL_PATH)/$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)
ifeq ($(TARGET_ENABLE_TA_SIGN), true)
-$(info $(shell mkdir $(ANDROID_BUILD_TOP)/$(LOCAL_PATH)/signed))
-$(info $(shell $(ANDROID_BUILD_TOP)/$(BOARD_AML_VENDOR_PATH)/tdk/ta_export/scripts/sign_ta_auto.py \
- --in=$(ANDROID_BUILD_TOP)/$(LOCAL_PATH)/$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX) \
- --out=$(ANDROID_BUILD_TOP)/$(LOCAL_PATH)/signed/$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)))
-LOCAL_SRC_FILES := signed/$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE):
+ @mkdir -p $(dir $@)
+ $(BOARD_AML_VENDOR_PATH)/tdk/ta_export/scripts/sign_ta_auto.py \
+ --in=$(KEYMASTER_UNSIGNED_TA) \
+ --out=$@ \
+ --keydir=$(BOARD_AML_TDK_KEY_PATH)
else
-LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)
-endif
+LOCAL_PREBUILT_MODULE_FILE := $(KEYMASTER_UNSIGNED_TA)
include $(BUILD_PREBUILT)
+endif
-
-# Unit tests for libkeymaster
include $(CLEAR_VARS)
-LOCAL_MODULE := amlkeymaster_tests
-LOCAL_SRC_FILES := \
- unit_test/android_keymaster_test.cpp \
- unit_test/android_keymaster_test_utils.cpp \
- unit_test/attestation_record.cpp
-# unit_test/attestation_record_test.cpp \
- unit_test/authorization_set_test.cpp \
-# unit_test/android_keymaster_messages_test.cpp \
- unit_test/hkdf_test.cpp \
- unit_test/hmac_test.cpp \
- unit_test/kdf1_test.cpp \
- unit_test/kdf2_test.cpp \
- unit_test/kdf_test.cpp \
- unit_test/key_blob_test.cpp \
- unit_test/keymaster_enforcement_test.cpp
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := 4.0/service.cpp \
+ 4.0/AmlogicKeymaster4Device.cpp \
+ ipc/amlogic_keymaster_ipc.cpp \
+ AmlogicKeymaster.cpp
+LOCAL_CFLAGS += -DAMLOGIC_MODIFY=1
LOCAL_C_INCLUDES := \
- external/boringssl/include \
- system/keymaster/include \
- system/keymaster \
- system/security/softkeymaster/include
+ $(LOCAL_PATH)/include \
+ $(BOARD_AML_VENDOR_PATH)/tdk/ca_export_arm/include
-LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS
-LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
-# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
-# Currently, if enabled, these flags will cause an internal error in Clang.
-LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
-LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := \
- libsoftkeymasterdevice \
- libkeymaster_messages \
- libcrypto \
- libsoftkeymaster \
- libkeymaster_portable \
- libhardware
-
-LOCAL_CFLAGS += -DANDROID_PLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware \
+ libhidlbase \
+ libhidltransport \
+ libteec \
+ libkeymaster_messages \
+ libkeymaster4 \
+ android.hardware.keymaster@4.0
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 26 && echo OK),OK)
-LOCAL_SHARED_LIBRARIES += libkeymaster1
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK)
+LOCAL_PROPRIETARY_MODULE := true
endif
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_NATIVE_TEST)
-
+LOCAL_REQUIRED_MODULES := $(KEYMASTER_TA_BINARY)
+LOCAL_MODULE := android.hardware.keymaster@4.0-service.amlogic
+LOCAL_INIT_RC := 4.0/android.hardware.keymaster@4.0-service.amlogic.rc
+include $(BUILD_EXECUTABLE)
diff --git a/aml_keymaster_device.cpp b/aml_keymaster_device.cpp
deleted file mode 100644
index 7a8c785..0000000
--- a/aml_keymaster_device.cpp
+++ b/dev/null
@@ -1,1021 +0,0 @@
-/*
- * Copyright 2014 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 "AmlKeymaster"
-
-#include <assert.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <openssl/sha.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <fstream>
-#include <iostream>
-#include <inttypes.h>
-
-#include <algorithm>
-#include <type_traits>
-
-#include <hardware/keymaster2.h>
-#include <keymaster/authorization_set.h>
-#include <log/log.h>
-#include <utils/String8.h>
-
-#include "keymaster_ipc.h"
-#include "aml_keymaster_device.h"
-#include "aml_keymaster_ipc.h"
-
-#ifndef KEYMASTER_TEMP_FAILURE_RETRY
-#define KEYMASTER_TEMP_FAILURE_RETRY(exp, retry) \
- ({ \
- __typeof__(exp) _rc; \
- int count = 0; \
- do { \
- _rc = (exp); \
- count ++; \
- } while (_rc != TEEC_SUCCESS && count < retry); \
- _rc; \
- })
-#endif
-
-const uint32_t RECV_BUF_SIZE = 66 * 1024;
-const uint32_t SEND_BUF_SIZE = (66 * 1024 - sizeof(struct keymaster_message) - 16 /* tipc header */);
-
-const size_t kMaximumAttestationChallengeLength = 128;
-const size_t kMaximumFinishInputLength = 64 * 1024;
-
-namespace keymaster {
-
-static keymaster_error_t translate_error(TEEC_Result err) {
- switch (err) {
- case TEEC_SUCCESS:
- return KM_ERROR_OK;
- case TEEC_ERROR_ACCESS_DENIED:
- return KM_ERROR_SECURE_HW_ACCESS_DENIED;
-
- case TEEC_ERROR_CANCEL:
- return KM_ERROR_OPERATION_CANCELLED;
-
- case TEEC_ERROR_NOT_IMPLEMENTED:
- return KM_ERROR_UNIMPLEMENTED;
-
- case TEEC_ERROR_OUT_OF_MEMORY:
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- case TEEC_ERROR_BUSY:
- return KM_ERROR_SECURE_HW_BUSY;
-
- case TEEC_ERROR_COMMUNICATION:
- return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
-
- case TEEC_ERROR_SHORT_BUFFER:
- return KM_ERROR_INVALID_INPUT_LENGTH;
-
- default:
- return KM_ERROR_UNKNOWN_ERROR;
- }
-}
-
-AmlKeymasterDevice::AmlKeymasterDevice(const hw_module_t* module) {
- static_assert(std::is_standard_layout<AmlKeymasterDevice>::value,
- "AmlKeymasterDevice must be standard layout");
- static_assert(offsetof(AmlKeymasterDevice, device_) == 0,
- "device_ must be the first member of AmlKeymasterDevice");
- static_assert(offsetof(AmlKeymasterDevice, device_.common) == 0,
- "common must be the first member of keymaster2_device");
-
- ALOGI("Creating device");
- ALOGD("Device address: %p", this);
-
- device_ = {};
-
- device_.common.tag = HARDWARE_DEVICE_TAG;
- device_.common.version = 1;
- device_.common.module = const_cast<hw_module_t*>(module);
- device_.common.close = close_device;
-
- device_.flags = KEYMASTER_SUPPORTS_EC;
-
- device_.configure = configure;
- device_.add_rng_entropy = add_rng_entropy;
- device_.generate_key = generate_key;
- device_.get_key_characteristics = get_key_characteristics;
- device_.import_key = import_key;
- device_.export_key = export_key;
- device_.attest_key = attest_key;
- device_.upgrade_key = upgrade_key;
- device_.delete_key = delete_key;
- device_.delete_all_keys = nullptr;
- device_.begin = begin;
- device_.update = update;
- device_.finish = finish;
- device_.abort = abort;
-
- KM_context.fd = 0;
- KM_session.ctx = NULL;
- KM_session.session_id = 0;
-
-
- TEEC_Result rc = KEYMASTER_TEMP_FAILURE_RETRY(aml_keymaster_connect(&KM_context, &KM_session), 100);
- error_ = translate_error(rc);
- if (rc != TEEC_SUCCESS) {
- ALOGE("failed to connect to keymaster (0x%x)", rc);
- error_ = KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
- return;
- }
-
- GetVersionRequest version_request;
- GetVersionResponse version_response;
- error_ = Send(KM_GET_VERSION, version_request, &version_response);
- if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
- ALOGE("\"Bad parameters\" error on GetVersion call. Version 0 is not supported.");
- error_ = KM_ERROR_VERSION_MISMATCH;
- return;
- }
- message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
- version_response.subminor_ver);
- if (message_version_ < 0) {
- // Can't translate version? Keymaster implementation must be newer.
- ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
- version_response.minor_ver, version_response.subminor_ver);
- error_ = KM_ERROR_VERSION_MISMATCH;
- }
-}
-
-AmlKeymasterDevice::~AmlKeymasterDevice() {
- if (KM_session.ctx != NULL)
- aml_keymaster_disconnect(&KM_context, &KM_session);
-}
-
-namespace {
-
-// Allocates a new buffer with malloc and copies the contents of |buffer| to it. Caller takes
-// ownership of the returned buffer.
-uint8_t* DuplicateBuffer(const uint8_t* buffer, size_t size) {
- uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(size));
- if (tmp) {
- memcpy(tmp, buffer, size);
- }
- return tmp;
-}
-
-template <typename RequestType>
-void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
- RequestType* request) {
- request->additional_params.Clear();
- if (client_id) {
- request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
- }
- if (app_data) {
- request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
- }
-}
-
-} // unnamed namespace
-
-struct tag_table_entry {
- const char *name;
- keymaster_tag_t tag;
-};
-
-static struct tag_table_entry tag_table[] =
-{
- {"KM_TAG_PURPOSE", KM_TAG_PURPOSE},
- {"KM_TAG_ALGORITHM", KM_TAG_ALGORITHM},
- {"KM_TAG_KEY_SIZE", KM_TAG_KEY_SIZE},
- {"KM_TAG_BLOCK_MODE", KM_TAG_BLOCK_MODE},
- {"KM_TAG_DIGEST", KM_TAG_DIGEST},
- {"KM_TAG_PADDING", KM_TAG_PADDING},
- {"KM_TAG_CALLER_NONCE", KM_TAG_CALLER_NONCE},
- {"KM_TAG_MIN_MAC_LENGTH", KM_TAG_MIN_MAC_LENGTH},
- {"KM_TAG_RSA_PUBLIC_EXPONENT", KM_TAG_RSA_PUBLIC_EXPONENT},
- {"KM_TAG_BLOB_USAGE_REQUIREMENTS", KM_TAG_BLOB_USAGE_REQUIREMENTS},
- {"KM_TAG_BOOTLOADER_ONLY", KM_TAG_BOOTLOADER_ONLY},
- {"KM_TAG_ACTIVE_DATETIME", KM_TAG_ACTIVE_DATETIME},
- {"KM_TAG_ORIGINATION_EXPIRE_DATETIME", KM_TAG_ORIGINATION_EXPIRE_DATETIME},
- {"KM_TAG_USAGE_EXPIRE_DATETIME",KM_TAG_USAGE_EXPIRE_DATETIME},
- {"KM_TAG_MIN_SECONDS_BETWEEN_OPS",KM_TAG_MIN_SECONDS_BETWEEN_OPS},
- {"KM_TAG_MAX_USES_PER_BOOT",KM_TAG_MAX_USES_PER_BOOT},
- {"KM_TAG_ALL_USERS", KM_TAG_ALL_USERS},
- {"KM_TAG_USER_ID", KM_TAG_USER_ID},
- {"KM_TAG_USER_SECURE_ID",KM_TAG_USER_SECURE_ID},
- {"KM_TAG_NO_AUTH_REQUIRED",KM_TAG_NO_AUTH_REQUIRED},
- {"KM_TAG_USER_AUTH_TYPE ", KM_TAG_USER_AUTH_TYPE},
- {"KM_TAG_AUTH_TIMEOUT ",KM_TAG_AUTH_TIMEOUT },
- {"KM_TAG_ALL_APPLICATIONS ", KM_TAG_ALL_APPLICATIONS },
- {"KM_TAG_APPLICATION_ID", KM_TAG_APPLICATION_ID},
- {"KM_TAG_APPLICATION_DATA ",KM_TAG_APPLICATION_DATA },
- {"KM_TAG_CREATION_DATETIME ",KM_TAG_CREATION_DATETIME },
- {"KM_TAG_ORIGIN ", KM_TAG_ORIGIN },
- {"KM_TAG_ROLLBACK_RESISTANT ", KM_TAG_ROLLBACK_RESISTANT },
- {"KM_TAG_ROOT_OF_TRUST", KM_TAG_ROOT_OF_TRUST},
- {"KM_TAG_ASSOCIATED_DATA ",KM_TAG_ASSOCIATED_DATA},
- {"KM_TAG_NONCE", KM_TAG_NONCE},
- {"KM_TAG_AUTH_TOKEN",KM_TAG_AUTH_TOKEN},
- {"KM_TAG_MAC_LENGTH", KM_TAG_MAC_LENGTH},
-};
-
-const size_t tag_table_size = sizeof(tag_table)/sizeof(struct tag_table_entry);
-
-void AmlKeymasterDevice::dump_tag_item_value(const char *name, const keymaster_key_param_t* item)
-{
- keymaster_tag_type_t type = KM_INVALID;
-
- if (item) {
- type = keymaster_tag_get_type(item->tag);
- switch (type) {
- case KM_ULONG:
- case KM_ULONG_REP:
- ALOGI("%s: %" PRIx64 "\n", name, item->long_integer);
- //printf("%s: %" PRIx64 "\n", name, item->long_integer);
- break;
- case KM_DATE:
- ALOGI("%s: %" PRIx64 "\n", name, item->date_time);
- //printf("%s: %" PRIx64 "\n", name, item->date_time);
- break;
- case KM_BYTES:
- case KM_BIGNUM:
- ALOGI("%s: blob data: %p, len: 0x%zx\n", name, item->blob.data, item->blob.data_length);
- //printf("%s: blob data: %p, len: 0x%zx\n", name, item->blob.data, item->blob.data_length);
- break;
- case KM_ENUM:
- case KM_ENUM_REP:
- ALOGI("%s: 0x%x\n", name, item->enumerated);
- //printf("%s: 0x%x\n", name, item->enumerated);
- break;
- case KM_BOOL:
- ALOGI("%s: 0x%x\n", name, item->boolean);
- //printf("%s: 0x%x\n", name, item->boolean);
- break;
- case KM_UINT:
- case KM_UINT_REP:
- ALOGI("%s: 0x%x\n", name, item->integer);
- //printf("%s: 0x%x\n", name, item->integer);
- break;
- default:
- ALOGI("%s: invalid type: %d\n", name, type);
- //printf("%s: invalid type: %d\n", name, type);
- break;
- }
- }
-}
-
-void AmlKeymasterDevice::dump_tags(const char *name, const keymaster_key_param_set_t *params)
-{
- size_t i = 0, j =0;
- keymaster_key_param_t* item = params->params;
-
- ALOGI("==== start dump %s, length (%zu)\n", name, params->length);
- //printf("==== start dump %s, length (%zu)\n", name, params->length);
- for (i = 0; i < params->length; i++) {
- for (j = 0; j < tag_table_size; j++) {
- if (tag_table[j].tag == item[i].tag) {
- dump_tag_item_value(tag_table[j].name, &item[i]);
- break;
- }
- }
- }
- ALOGI("==== end dump %s\n", name);
- //printf("==== end dump %s\n", name);
-}
-
-keymaster_error_t AmlKeymasterDevice::configure(const keymaster_key_param_set_t* params) {
- ALOGD("Device received configure\n");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!params) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
-
- AuthorizationSet params_copy(*params);
- ConfigureRequest request;
- if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) ||
- !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) {
- ALOGD("Configuration parameters must contain OS version and patch level");
- return KM_ERROR_INVALID_ARGUMENT;
- }
-
- ConfigureResponse response;
- keymaster_error_t err = Send(KM_CONFIGURE, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::add_rng_entropy(const uint8_t* data, size_t data_length) {
- ALOGD("Device received add_rng_entropy");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
-
- AddEntropyRequest request;
- request.random_data.Reinitialize(data, data_length);
- AddEntropyResponse response;
- return Send(KM_ADD_RNG_ENTROPY, request, &response);
-}
-
-keymaster_error_t AmlKeymasterDevice::simple_bin2ascii(uint8_t *data, size_t data_length, char *out) {
- for (size_t i = 0; i < data_length; i++) {
- if (((data[i] & 0xf0) >> 4) < 0xa)
- out[i * 2] = ((data[i] & 0xf0) >> 4) + 48;
- else
- out[i * 2] = ((data[i] & 0xf0) >> 4) + 87;
- if ((data[i] & 0xf) < 0xa)
- out[i * 2 + 1] = (data[i] & 0xf) + 48;
- else
- out[i * 2 + 1] = (data[i] & 0xf) + 87;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::store_encrypted_key(keymaster_key_blob_t* key_blob) {
- SHA256_CTX sha256_ctx;
- UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH + 1]);
- UniquePtr<char[]> name_buf(new (std::nothrow) char [SHA256_DIGEST_LENGTH * 2 + 1]);
- std::ofstream out;
- char name[256];
-
- // Hash key data to create filename.
- Eraser sha256_ctx_eraser(sha256_ctx);
- memset(name_buf.get(), 0, SHA256_DIGEST_LENGTH * 2 + 1);
- SHA256_Init(&sha256_ctx);
- SHA256_Update(&sha256_ctx, key_blob->key_material, key_blob->key_material_size);
- SHA256_Final(hash_buf.get(), &sha256_ctx);
-
- simple_bin2ascii(hash_buf.get(), SHA256_DIGEST_LENGTH, name_buf.get());
- name_buf[SHA256_DIGEST_LENGTH * 2] = '\0';
- sprintf(name, "/data/tee/%s", name_buf.get());
- out.open(name, std::ofstream::out | std::ofstream::binary);
- if (out.is_open()) {
- out.write((const char *)key_blob->key_material, key_blob->key_material_size);
- out.close();
- } else {
- ALOGE("error opening key files\n");
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::delete_encrypted_key(const keymaster_key_blob_t* key_blob) {
- SHA256_CTX sha256_ctx;
- UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH + 1]);
- UniquePtr<char[]> name_buf(new (std::nothrow) char [SHA256_DIGEST_LENGTH * 2 + 1]);
- std::ofstream out;
- char name[256];
- int result = -1;
-
- // Hash key data to get filename.
- Eraser sha256_ctx_eraser(sha256_ctx);
- memset(name_buf.get(), 0, SHA256_DIGEST_LENGTH * 2 + 1);
- SHA256_Init(&sha256_ctx);
- SHA256_Update(&sha256_ctx, key_blob->key_material, key_blob->key_material_size);
- SHA256_Final(hash_buf.get(), &sha256_ctx);
-
- simple_bin2ascii(hash_buf.get(), SHA256_DIGEST_LENGTH, name_buf.get());
- name_buf[SHA256_DIGEST_LENGTH * 2] = '\0';
- sprintf(name, "/data/tee/%s", name_buf.get());
- out.open(name, std::ofstream::out | std::ofstream::binary);
- result = unlink(name);
-
- if (!result) {
- return KM_ERROR_OK;
- } else {
- ALOGE("cannot locate %s\n", name);
- return KM_ERROR_INVALID_OPERATION_HANDLE;
- }
-}
-
-keymaster_error_t AmlKeymasterDevice::generate_key(
- const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics) {
- ALOGD("Device received generate_key");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!params) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!key_blob) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- GenerateKeyRequest request(message_version_);
- request.key_description.Reinitialize(*params);
- request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
-
- GenerateKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_GENERATE_KEY, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- key_blob->key_material_size = response.key_blob.key_material_size;
- key_blob->key_material =
- DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
- if (!key_blob->key_material) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
-
- if (characteristics) {
- response.enforced.CopyToParamSet(&characteristics->hw_enforced);
- response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::get_key_characteristics(
- const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) {
- ALOGD("Device received get_key_characteristics");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!key_blob || !key_blob->key_material) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!characteristics) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- GetKeyCharacteristicsRequest request;
- request.SetKeyMaterial(*key_blob);
- AddClientAndAppData(client_id, app_data, &request);
-
- GetKeyCharacteristicsResponse response;
- keymaster_error_t err = Send(KM_GET_KEY_CHARACTERISTICS, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- response.enforced.CopyToParamSet(&characteristics->hw_enforced);
- response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::import_key(
- const keymaster_key_param_set_t* params, keymaster_key_format_t key_format,
- const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics) {
- ALOGD("Device received import_key");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!params || !key_data) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!key_blob) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- ImportKeyRequest request(message_version_);
- request.key_description.Reinitialize(*params);
- request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
-
- dump_tags("import", &request.key_description);
- request.key_format = key_format;
- request.SetKeyMaterial(key_data->data, key_data->data_length);
-
- ImportKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_IMPORT_KEY, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- key_blob->key_material_size = response.key_blob.key_material_size;
- key_blob->key_material =
- DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
- if (!key_blob->key_material) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
-
- dump_tags("hw", &response.enforced);
- dump_tags("sw", &response.unenforced);
- if (characteristics) {
- response.enforced.CopyToParamSet(&characteristics->hw_enforced);
- response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::export_key(keymaster_key_format_t export_format,
- const keymaster_key_blob_t* key_to_export,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_blob_t* export_data) {
- ALOGD("Device received export_key");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!key_to_export || !key_to_export->key_material) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!export_data) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- export_data->data = nullptr;
- export_data->data_length = 0;
-
- ExportKeyRequest request(message_version_);
- request.key_format = export_format;
- request.SetKeyMaterial(*key_to_export);
- AddClientAndAppData(client_id, app_data, &request);
-
- ExportKeyResponse response(message_version_);
- keymaster_error_t err = Send(KM_EXPORT_KEY, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- export_data->data_length = response.key_data_length;
- export_data->data = DuplicateBuffer(response.key_data, response.key_data_length);
- if (!export_data->data) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::attest_key(const keymaster_key_blob_t* key_to_attest,
- const keymaster_key_param_set_t* attest_params,
- keymaster_cert_chain_t* cert_chain) {
- ALOGD("Device received attest_key");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!key_to_attest || !attest_params) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!cert_chain) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- cert_chain->entry_count = 0;
- cert_chain->entries = nullptr;
-
- AttestKeyRequest request;
- request.SetKeyMaterial(*key_to_attest);
- request.attest_params.Reinitialize(*attest_params);
-
- keymaster_blob_t attestation_challenge = {};
- request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge);
- if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) {
- ALOGE("%zu-byte attestation challenge; only %zu bytes allowed",
- attestation_challenge.data_length, kMaximumAttestationChallengeLength);
- return KM_ERROR_INVALID_INPUT_LENGTH;
- }
-
- AttestKeyResponse response;
- keymaster_error_t err = Send(KM_ATTEST_KEY, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- // Allocate and clear storage for cert_chain.
- keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
- cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
- malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
- if (!cert_chain->entries) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- cert_chain->entry_count = rsp_chain.entry_count;
- for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count)) {
- entry = {};
- }
-
- // Copy cert_chain contents
- size_t i = 0;
- for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) {
- cert_chain->entries[i].data = DuplicateBuffer(entry.data, entry.data_length);
- if (!cert_chain->entries[i].data) {
- keymaster_free_cert_chain(cert_chain);
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- cert_chain->entries[i].data_length = entry.data_length;
- ++i;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::upgrade_key(const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key) {
- ALOGD("Device received upgrade_key");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!key_to_upgrade || !upgrade_params) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!upgraded_key) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- UpgradeKeyRequest request;
- request.SetKeyMaterial(*key_to_upgrade);
- request.upgrade_params.Reinitialize(*upgrade_params);
-
- UpgradeKeyResponse response;
- keymaster_error_t err = Send(KM_UPGRADE_KEY, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- upgraded_key->key_material_size = response.upgraded_key.key_material_size;
- upgraded_key->key_material = DuplicateBuffer(response.upgraded_key.key_material,
- response.upgraded_key.key_material_size);
- if (!upgraded_key->key_material) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::delete_key(const keymaster_key_blob_t* key) {
- (void)key;
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::begin(keymaster_purpose_t purpose,
- const keymaster_key_blob_t* key,
- const keymaster_key_param_set_t* in_params,
- keymaster_key_param_set_t* out_params,
- keymaster_operation_handle_t* operation_handle) {
- ALOGD("Device received begin");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!key || !key->key_material) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!operation_handle) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- if (out_params) {
- *out_params = {};
- }
-
- BeginOperationRequest request;
- request.purpose = purpose;
- request.SetKeyMaterial(*key);
- request.additional_params.Reinitialize(*in_params);
-
- BeginOperationResponse response;
- keymaster_error_t err = Send(KM_BEGIN_OPERATION, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- if (response.output_params.size() > 0) {
- if (out_params) {
- response.output_params.CopyToParamSet(out_params);
- } else {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
- }
- *operation_handle = response.op_handle;
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::update(keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input,
- size_t* input_consumed,
- keymaster_key_param_set_t* out_params,
- keymaster_blob_t* output) {
- ALOGD("Device received update");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (!input) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
- }
- if (!input_consumed) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- if (out_params) {
- *out_params = {};
- }
- if (output) {
- *output = {};
- }
-
- UpdateOperationRequest request;
- request.op_handle = operation_handle;
- if (in_params) {
- request.additional_params.Reinitialize(*in_params);
- }
- if (input && input->data_length > 0) {
- size_t max_input_size = SEND_BUF_SIZE - request.SerializedSize();
- request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size));
- }
-
- UpdateOperationResponse response;
- keymaster_error_t err = Send(KM_UPDATE_OPERATION, request, &response);
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- if (response.output_params.size() > 0) {
- if (out_params) {
- response.output_params.CopyToParamSet(out_params);
- } else {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
- }
- *input_consumed = response.input_consumed;
- if (output) {
- output->data_length = response.output.available_read();
- output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
- if (!output->data) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- } else if (response.output.available_read() > 0) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::finish(keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input,
- const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params,
- keymaster_blob_t* output) {
- ALOGD("Device received finish");
-
- bool size_exceeded = false;
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
- if (input && input->data_length > kMaximumFinishInputLength) {
- ALOGE("%zu-byte input to finish; only %zu bytes allowed",
- input->data_length, kMaximumFinishInputLength);
- size_exceeded = true;
- }
-
- if (out_params) {
- *out_params = {};
- }
- if (output) {
- *output = {};
- }
-
- FinishOperationRequest request;
- request.op_handle = operation_handle;
- if (signature && signature->data && signature->data_length > 0) {
- request.signature.Reinitialize(signature->data, signature->data_length);
- }
- if (input && input->data && input->data_length) {
- /* sending fake request to close operation handle */
- if (size_exceeded)
- request.input.Reinitialize(input->data, 1);
- else
- request.input.Reinitialize(input->data, input->data_length);
- }
- if (in_params) {
- request.additional_params.Reinitialize(*in_params);
- }
-
- FinishOperationResponse response;
- keymaster_error_t err = Send(KM_FINISH_OPERATION, request, &response);
- /* drop result in case of fake request */
- if (size_exceeded)
- return KM_ERROR_INVALID_INPUT_LENGTH;
- if (err != KM_ERROR_OK) {
- return err;
- }
-
- if (response.output_params.size() > 0) {
- if (out_params) {
- response.output_params.CopyToParamSet(out_params);
- } else {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
- }
- if (output) {
- output->data_length = response.output.available_read();
- output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
- if (!output->data) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- } else if (response.output.available_read() > 0) {
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
- }
-
- return KM_ERROR_OK;
-}
-
-keymaster_error_t AmlKeymasterDevice::abort(keymaster_operation_handle_t operation_handle) {
- ALOGD("Device received abort");
-
- if (error_ != KM_ERROR_OK) {
- return error_;
- }
-
- AbortOperationRequest request;
- request.op_handle = operation_handle;
- AbortOperationResponse response;
- return Send(KM_ABORT_OPERATION, request, &response);
-}
-
-hw_device_t* AmlKeymasterDevice::hw_device() {
- return &device_.common;
-}
-
-static inline AmlKeymasterDevice* convert_device(const keymaster2_device_t* dev) {
- return reinterpret_cast<AmlKeymasterDevice*>(const_cast<keymaster2_device_t*>(dev));
-}
-
-/* static */
-int AmlKeymasterDevice::close_device(hw_device_t* dev) {
- delete reinterpret_cast<AmlKeymasterDevice*>(dev);
- return 0;
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::configure(const keymaster2_device_t* dev,
- const keymaster_key_param_set_t* params) {
- return convert_device(dev)->configure(params);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev,
- const uint8_t* data, size_t data_length) {
- return convert_device(dev)->add_rng_entropy(data, data_length);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::generate_key(
- const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
- keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
- return convert_device(dev)->generate_key(params, key_blob, characteristics);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::get_key_characteristics(
- const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
- const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
- keymaster_key_characteristics_t* characteristics) {
- return convert_device(dev)->get_key_characteristics(key_blob, client_id, app_data,
- characteristics);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::import_key(
- const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
- keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
- keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
- return convert_device(dev)->import_key(params, key_format, key_data, key_blob, characteristics);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::export_key(const keymaster2_device_t* dev,
- keymaster_key_format_t export_format,
- const keymaster_key_blob_t* key_to_export,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_blob_t* export_data) {
- return convert_device(dev)->export_key(export_format, key_to_export, client_id, app_data,
- export_data);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::attest_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_to_attest,
- const keymaster_key_param_set_t* attest_params,
- keymaster_cert_chain_t* cert_chain) {
- return convert_device(dev)->attest_key(key_to_attest, attest_params, cert_chain);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::upgrade_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key) {
- return convert_device(dev)->upgrade_key(key_to_upgrade, upgrade_params, upgraded_key);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::delete_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_blob) {
- return convert_device(dev)->delete_key(key_blob);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::begin(const keymaster2_device_t* dev,
- keymaster_purpose_t purpose,
- const keymaster_key_blob_t* key,
- const keymaster_key_param_set_t* in_params,
- keymaster_key_param_set_t* out_params,
- keymaster_operation_handle_t* operation_handle) {
- return convert_device(dev)->begin(purpose, key, in_params, out_params, operation_handle);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::update(
- const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input,
- size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) {
- return convert_device(dev)->update(operation_handle, in_params, input, input_consumed,
- out_params, output);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::finish(const keymaster2_device_t* dev,
- keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input,
- const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params,
- keymaster_blob_t* output) {
- return convert_device(dev)->finish(operation_handle, in_params, input, signature, out_params,
- output);
-}
-
-/* static */
-keymaster_error_t AmlKeymasterDevice::abort(const keymaster2_device_t* dev,
- keymaster_operation_handle_t operation_handle) {
- return convert_device(dev)->abort(operation_handle);
-}
-
-keymaster_error_t AmlKeymasterDevice::Send(uint32_t command, const Serializable& req,
- KeymasterResponse* rsp) {
- uint32_t req_size = req.SerializedSize();
-
- if (req_size > SEND_BUF_SIZE) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- //uint8_t send_buf[SEND_BUF_SIZE];
- UniquePtr<uint8_t[]> send_buf (new (std::nothrow) uint8_t[SEND_BUF_SIZE]);
- if (!send_buf.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- Eraser send_buf_eraser(send_buf.get(), SEND_BUF_SIZE);
- req.Serialize(send_buf.get(), send_buf.get() + req_size);
-
- // Send it
- //uint8_t recv_buf[RECV_BUF_SIZE];
- UniquePtr<uint8_t[]> recv_buf (new (std::nothrow) uint8_t[RECV_BUF_SIZE]);
- if (!recv_buf.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- Eraser recv_buf_eraser(recv_buf.get(), RECV_BUF_SIZE);
- uint32_t rsp_size = RECV_BUF_SIZE;
- ALOGD("Sending cmd: %u with %d byte request\n", command, (int)req.SerializedSize());
- TEEC_Result rc = aml_keymaster_call(&KM_session, command, send_buf.get(), req_size, recv_buf.get(), &rsp_size);
- if (rc != TEEC_SUCCESS) {
- return translate_error(rc);
- } else {
- ALOGD("Received %d byte response\n", rsp_size);
- }
-
- const keymaster_message* msg = (keymaster_message*)recv_buf.get();
- const uint8_t* p = msg->payload;
- if (!rsp->Deserialize(&p, p + rsp_size)) {
- ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
- return KM_ERROR_UNKNOWN_ERROR;
- } else if (rsp->error != KM_ERROR_OK) {
- ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
- return rsp->error;
- }
- return rsp->error;
-}
-
-} // namespace keymaster
diff --git a/aml_keymaster_device.h b/aml_keymaster_device.h
deleted file mode 100644
index 2066a7c..0000000
--- a/aml_keymaster_device.h
+++ b/dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2014 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 AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_
-#define AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_
-
-#include <hardware/keymaster2.h>
-#include <keymaster/android_keymaster_messages.h>
-
-extern "C" {
-#include <tee_client_api.h>
-}
-
-namespace keymaster {
-
-/**
- * Aml Keymaster device.
- *
- * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
- * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
- * no data members which aren't standard layout), and device_ must be the first data member.
- * Assertions in the constructor validate compliance with those constraints.
- */
-class AmlKeymasterDevice {
- public:
- /*
- * These are the only symbols that will be exported by libamlkeymaster. All functionality
- * can be reached via the function pointers in device_.
- */
- __attribute__((visibility("default"))) explicit AmlKeymasterDevice(const hw_module_t* module);
- __attribute__((visibility("default"))) hw_device_t* hw_device();
-
- ~AmlKeymasterDevice();
-
- keymaster_error_t session_error() { return error_; }
-
- keymaster_error_t configure(const keymaster_key_param_set_t* params);
- keymaster_error_t add_rng_entropy(const uint8_t* data, size_t data_length);
- keymaster_error_t generate_key(const keymaster_key_param_set_t* params,
- keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics);
- keymaster_error_t get_key_characteristics(const keymaster_key_blob_t* key_blob,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_key_characteristics_t* character);
- keymaster_error_t import_key(const keymaster_key_param_set_t* params,
- keymaster_key_format_t key_format,
- const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics);
- keymaster_error_t export_key(keymaster_key_format_t export_format,
- const keymaster_key_blob_t* key_to_export,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data, keymaster_blob_t* export_data);
- keymaster_error_t attest_key(const keymaster_key_blob_t* key_to_attest,
- const keymaster_key_param_set_t* attest_params,
- keymaster_cert_chain_t* cert_chain);
- keymaster_error_t upgrade_key(const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key);
- keymaster_error_t delete_key(const keymaster_key_blob_t* key);
- keymaster_error_t begin(keymaster_purpose_t purpose, const keymaster_key_blob_t* key,
- const keymaster_key_param_set_t* in_params,
- keymaster_key_param_set_t* out_params,
- keymaster_operation_handle_t* operation_handle);
- keymaster_error_t update(keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, size_t* input_consumed,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
- keymaster_error_t finish(keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
- keymaster_error_t abort(keymaster_operation_handle_t operation_handle);
-
- keymaster_error_t store_encrypted_key(keymaster_key_blob_t* key_blob);
- keymaster_error_t delete_encrypted_key(const keymaster_key_blob_t* key_blob);
- keymaster_error_t simple_bin2ascii(uint8_t *data, size_t data_length, char *out);
- private:
- keymaster_error_t Send(uint32_t command, const Serializable& request,
- KeymasterResponse* response);
-
- /*
- * These static methods are the functions referenced through the function pointers in
- * keymaster_device. They're all trivial wrappers.
- */
- static int close_device(hw_device_t* dev);
- static keymaster_error_t configure(const keymaster2_device_t* dev,
- const keymaster_key_param_set_t* params);
- static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data,
- size_t data_length);
- static keymaster_error_t generate_key(const keymaster2_device_t* dev,
- const keymaster_key_param_set_t* params,
- keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics);
- static keymaster_error_t get_key_characteristics(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_blob,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_key_characteristics_t* character);
- static keymaster_error_t import_key(const keymaster2_device_t* dev,
- const keymaster_key_param_set_t* params,
- keymaster_key_format_t key_format,
- const keymaster_blob_t* key_data,
- keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t* characteristics);
- static keymaster_error_t export_key(const keymaster2_device_t* dev,
- keymaster_key_format_t export_format,
- const keymaster_key_blob_t* key_to_export,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_blob_t* export_data);
- static keymaster_error_t attest_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_to_attest,
- const keymaster_key_param_set_t* attest_params,
- keymaster_cert_chain_t* cert_chain);
- static keymaster_error_t upgrade_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key_to_upgrade,
- const keymaster_key_param_set_t* upgrade_params,
- keymaster_key_blob_t* upgraded_key);
- static keymaster_error_t delete_key(const keymaster2_device_t* dev,
- const keymaster_key_blob_t* key);
- static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev);
- static keymaster_error_t begin(const keymaster2_device_t* dev, keymaster_purpose_t purpose,
- const keymaster_key_blob_t* key,
- const keymaster_key_param_set_t* in_params,
- keymaster_key_param_set_t* out_params,
- keymaster_operation_handle_t* operation_handle);
- static keymaster_error_t update(const keymaster2_device_t* dev,
- keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, size_t* input_consumed,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
- static keymaster_error_t finish(const keymaster2_device_t* dev,
- keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
- static keymaster_error_t abort(const keymaster2_device_t* dev,
- keymaster_operation_handle_t operation_handle);
-
- void dump_tags(const char *name, const keymaster_key_param_set_t *params);
- void dump_tag_item_value(const char *name, const keymaster_key_param_t* item);
-
- keymaster2_device_t device_;
- keymaster_error_t error_;
- int32_t message_version_;
-
- TEEC_Context KM_context;
- TEEC_Session KM_session;
-};
-
-#if ANDROID_PLATFORM_SDK_VERSION == 26 //8.0
-struct ConfigureRequest : public KeymasterMessage {
- explicit ConfigureRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
-
- size_t SerializedSize() const override { return sizeof(os_version) + sizeof(os_patchlevel); }
- uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
- buf = append_uint32_to_buf(buf, end, os_version);
- return append_uint32_to_buf(buf, end, os_patchlevel);
- }
- bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
- return copy_uint32_from_buf(buf_ptr, end, &os_version) &&
- copy_uint32_from_buf(buf_ptr, end, &os_patchlevel);
- }
-
- uint32_t os_version;
- uint32_t os_patchlevel;
-};
-
-struct ConfigureResponse : public KeymasterResponse {
- explicit ConfigureResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
- size_t NonErrorSerializedSize() const override { return 0; }
- uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
- bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
-};
-#endif
-
-} // namespace keymaster
-
-#endif // AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_
diff --git a/aml_keymaster_ipc.cpp b/aml_keymaster_ipc.cpp
deleted file mode 100644
index 7270db6..0000000
--- a/aml_keymaster_ipc.cpp
+++ b/dev/null
@@ -1,128 +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.
- */
-
-#define LOG_TAG "AmlKeymaster"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "keymaster_ipc.h"
-#include "aml_keymaster_ipc.h"
-
-TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s) {
- TEEC_Result result = TEEC_SUCCESS;
- TEEC_UUID svc_id = TA_KEYMASTER_UUID;
- TEEC_Operation operation;
- uint32_t err_origin;
- struct timespec time;
- uint64_t millis = 0;
-
- memset(&operation, 0, sizeof(operation));
-
- /* Initialize Context */
- result = TEEC_InitializeContext(NULL, c);
-
- if (result != TEEC_SUCCESS) {
- ALOGD("TEEC_InitializeContext failed with error = %x\n", result);
- return result;
- }
- /* Open Session */
- result = TEEC_OpenSession(c, s, &svc_id,
- TEEC_LOGIN_PUBLIC,
- NULL, NULL,
- &err_origin);
-
- if (result != TEEC_SUCCESS) {
- ALOGD("TEEC_Opensession failed with code 0x%x origin 0x%x",result, err_origin);
- TEEC_FinalizeContext(c);
- return result;
- }
-
- int res = clock_gettime(CLOCK_BOOTTIME, &time);
- if (res < 0)
- millis = 0;
- else
- millis = (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
-
- /* Init TA */
- operation.paramTypes = TEEC_PARAM_TYPES(
- TEEC_VALUE_INPUT, TEEC_NONE,
- TEEC_NONE, TEEC_NONE);
-
- operation.params[0].value.a = (millis >> 32);
- operation.params[0].value.b = (millis & 0xffffffff);
-
- result = TEEC_InvokeCommand(s,
- KM_TA_INIT,
- &operation,
- NULL);
-
- ALOGE("create id: %d, ctx: %p, ctx: %p\n", s->session_id, s->ctx, c);
- return result;
-}
-
-TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
- uint32_t* out_size) {
- TEEC_Result res = TEEC_SUCCESS;
- TEEC_Operation op;
- uint32_t ret_orig;
-
- memset(&op, 0, sizeof(op));
-
- op.params[0].tmpref.buffer = in;
- op.params[0].tmpref.size = in_size;
- op.params[1].tmpref.buffer = out;
- op.params[1].tmpref.size = *out_size;
- op.paramTypes = TEEC_PARAM_TYPES(
- TEEC_MEMREF_TEMP_INPUT,
- TEEC_MEMREF_TEMP_OUTPUT,
- TEEC_VALUE_OUTPUT,
- TEEC_NONE);
-
- ALOGE("id: %d, ctx: %p, cmd: %d\n", s->session_id, s->ctx, cmd);
- res = TEEC_InvokeCommand(s, cmd, &op, &ret_orig);
- if (res != TEEC_SUCCESS) {
- ALOGE("Invoke cmd: %u failed with res(%x), ret_orig(%x), return(%d)\n",
- cmd, res, ret_orig, op.params[2].value.a);
- } else {
- *out_size = op.params[2].value.b;
- }
-
- return res;
-}
-
-TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s) {
- TEEC_Operation operation;
- TEEC_Result result = TEEC_SUCCESS;
-
- operation.paramTypes = TEEC_PARAM_TYPES(
- TEEC_NONE, TEEC_NONE,
- TEEC_NONE, TEEC_NONE);
-
- result = TEEC_InvokeCommand(s,
- KM_TA_TERM,
- &operation,
- NULL);
-
- TEEC_CloseSession(s);
- TEEC_FinalizeContext(c);
-
- return result;
-}
diff --git a/aml_keymaster_ipc.h b/aml_keymaster_ipc.h
deleted file mode 100644
index fa4a2da..0000000
--- a/aml_keymaster_ipc.h
+++ b/dev/null
@@ -1,33 +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 AML_KEYMASTER_AML_KEYMASTER_IPC_H_
-#define AML_KEYMASTER_AML_KEYMASTER_IPC_H_
-
-extern "C" {
-#include <tee_client_api.h>
-}
-
-__BEGIN_DECLS
-
-TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s);
-TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
- uint32_t* out_size);
-TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s);
-
-__END_DECLS
-
-#endif // AML_KEYMASTER_AML_KEYMASTER_IPC_H_
diff --git a/include/amlogic_keymaster/AmlogicKeymaster.h b/include/amlogic_keymaster/AmlogicKeymaster.h
new file mode 100755
index 0000000..4aacc38
--- a/dev/null
+++ b/include/amlogic_keymaster/AmlogicKeymaster.h
@@ -0,0 +1,86 @@
+/*
+ * 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 TRUSTY_KEYMASTER_H_
+#define TRUSTY_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+#include <amlogic_keymaster/ipc/amlogic_keymaster_ipc.h>
+#if AMLOGIC_MODIFY
+#include <amlogic_keymaster/amlogic_keymaster_messages.h>
+
+extern "C" {
+#include <tee_client_api.h>
+}
+#endif
+namespace keymaster {
+
+class AmlogicKeymaster {
+ public:
+ AmlogicKeymaster();
+ ~AmlogicKeymaster();
+ int Initialize();
+ void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
+ void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+ SupportedAlgorithmsResponse* response);
+ void SupportedBlockModes(const SupportedBlockModesRequest& request,
+ SupportedBlockModesResponse* response);
+ void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+ SupportedPaddingModesResponse* response);
+ void SupportedDigests(const SupportedDigestsRequest& request,
+ SupportedDigestsResponse* response);
+ void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+ SupportedImportFormatsResponse* response);
+ void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+ SupportedExportFormatsResponse* response);
+ void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
+ void Configure(const ConfigureRequest& request, ConfigureResponse* response);
+ void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+ void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+ GetKeyCharacteristicsResponse* response);
+ void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+ void ImportWrappedKey(const ImportWrappedKeyRequest& request,
+ ImportWrappedKeyResponse* response);
+ void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+ void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+ void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
+ void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+ void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+ void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
+ void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
+ void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
+ void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
+ GetHmacSharingParametersResponse GetHmacSharingParameters();
+ ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
+ VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
+#if AMLOGIC_MODIFY
+ /* Move ForwardCommand from static method into class in order to access private members */
+ void ForwardCommand(enum keymaster_command command, const Serializable& req, KeymasterResponse* rsp);
+ private:
+ void SetBootParams(SetBootParamsRequest& request, SetBootParamsResponse* response);
+#if 0
+ bool HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex);
+ bool NibbleValue(const char& c, uint8_t* value);
+ std::string hex2bin(std::string const& s);
+#endif
+ TEEC_Context KM_context;
+ TEEC_Session KM_session;
+#endif
+};
+
+} // namespace keymaster
+
+#endif // TRUSTY_KEYMASTER_H_
diff --git a/include/amlogic_keymaster/AmlogicKeymaster4Device.h b/include/amlogic_keymaster/AmlogicKeymaster4Device.h
new file mode 100755
index 0000000..f4225eb
--- a/dev/null
+++ b/include/amlogic_keymaster/AmlogicKeymaster4Device.h
@@ -0,0 +1,105 @@
+/*
+ **
+ ** 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 keymaster_V4_0_AmlogicKeymaster4Device_H_
+#define keymaster_V4_0_AmlogicKeymaster4Device_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <hidl/Status.h>
+#include <amlogic_keymaster/AmlogicKeymaster.h>
+
+namespace keymaster {
+
+namespace V4_0 {
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::keymaster::V4_0::ErrorCode;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HmacSharingParameters;
+using ::android::hardware::keymaster::V4_0::IKeymasterDevice;
+using ::android::hardware::keymaster::V4_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V4_0::KeyFormat;
+using ::android::hardware::keymaster::V4_0::KeyParameter;
+using ::android::hardware::keymaster::V4_0::KeyPurpose;
+using ::android::hardware::keymaster::V4_0::SecurityLevel;
+using ::android::hardware::keymaster::V4_0::Tag;
+using ::android::hardware::keymaster::V4_0::VerificationToken;
+
+class AmlogicKeymaster4Device : public IKeymasterDevice {
+ public:
+ explicit AmlogicKeymaster4Device(AmlogicKeymaster* impl);
+ virtual ~AmlogicKeymaster4Device();
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override;
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override;
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+ computeSharedHmac_cb) override;
+ Return<void> verifyAuthorization(uint64_t challenge,
+ const hidl_vec<KeyParameter>& parametersToVerify,
+ const HardwareAuthToken& authToken,
+ verifyAuthorization_cb _hidl_cb) override;
+ Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override;
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override;
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+ const hidl_vec<uint8_t>& wrappingKeyBlob,
+ const hidl_vec<uint8_t>& maskingKey,
+ const hidl_vec<KeyParameter>& unwrappingParams,
+ uint64_t passwordSid, uint64_t biometricSid,
+ importWrappedKey_cb _hidl_cb) override;
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override;
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override;
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override;
+ Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<ErrorCode> deleteAllKeys() override;
+ Return<ErrorCode> destroyAttestationIds() override;
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override;
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+ Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+ private:
+ std::unique_ptr<::keymaster::AmlogicKeymaster> impl_;
+};
+
+} // namespace V4_0
+} // namespace keymaster
+
+#endif // keymaster_V4_0_AmlogicKeymaster4Device_H_
diff --git a/include/amlogic_keymaster/amlogic_keymaster_messages.h b/include/amlogic_keymaster/amlogic_keymaster_messages.h
new file mode 100755
index 0000000..a83aa1f
--- a/dev/null
+++ b/include/amlogic_keymaster/amlogic_keymaster_messages.h
@@ -0,0 +1,222 @@
+/*
+ * 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 TRUSTY_APP_KEYMASTER_TRUSTY_KEYMASTER_MESSAGES_H_
+#define TRUSTY_APP_KEYMASTER_TRUSTY_KEYMASTER_MESSAGES_H_
+
+#include <keymaster/android_keymaster_messages.h>
+
+namespace keymaster {
+
+/**
+ * Generic struct for Keymaster requests which hold a single raw buffer.
+ */
+struct RawBufferRequest : public KeymasterMessage {
+ explicit RawBufferRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return data.SerializedSize(); }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ return data.Serialize(buf, end);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return data.Deserialize(buf_ptr, end);
+ }
+
+ Buffer data;
+};
+
+/**
+ * Generic struct for Keymaster responses which hold a single raw buffer.
+ */
+struct RawBufferResponse : public KeymasterResponse {
+ explicit RawBufferResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterResponse(ver) {}
+
+ size_t NonErrorSerializedSize() const override {
+ return data.SerializedSize();
+ }
+ uint8_t* NonErrorSerialize(uint8_t* buf,
+ const uint8_t* end) const override {
+ return data.Serialize(buf, end);
+ }
+ bool NonErrorDeserialize(const uint8_t** buf_ptr,
+ const uint8_t* end) override {
+ return data.Deserialize(buf_ptr, end);
+ }
+
+ Buffer data;
+};
+
+/**
+ * Generic struct for Keymaster responses which have no specialized response
+ * data.
+ */
+struct NoResponse : public KeymasterResponse {
+ explicit NoResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterResponse(ver) {}
+
+ size_t NonErrorSerializedSize() const override { return 0; }
+ uint8_t* NonErrorSerialize(uint8_t* buf,
+ const uint8_t* end) const override {
+ (void)end;
+ return buf;
+ }
+ bool NonErrorDeserialize(const uint8_t** buf_ptr,
+ const uint8_t* end) override {
+ (void)buf_ptr;
+ (void)end;
+ return true;
+ }
+};
+
+struct NoRequest : public KeymasterMessage {
+ explicit NoRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return 0; }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ (void)end;
+ return buf;
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ (void)buf_ptr;
+ (void)end;
+ return true;
+ }
+};
+
+struct SetBootParamsRequest : public KeymasterMessage {
+ explicit SetBootParamsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override {
+ return (sizeof(os_version) + sizeof(os_patchlevel) +
+ sizeof(device_locked) + sizeof(verified_boot_state) +
+ verified_boot_key.SerializedSize() +
+ verified_boot_hash.SerializedSize());
+ }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ buf = append_uint32_to_buf(buf, end, os_version);
+ buf = append_uint32_to_buf(buf, end, os_patchlevel);
+ buf = append_uint32_to_buf(buf, end, device_locked);
+ buf = append_uint32_to_buf(buf, end, verified_boot_state);
+ buf = verified_boot_key.Serialize(buf, end);
+ return verified_boot_hash.Serialize(buf, end);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &os_version) &&
+ copy_uint32_from_buf(buf_ptr, end, &os_patchlevel) &&
+ copy_uint32_from_buf(buf_ptr, end, &device_locked) &&
+ copy_uint32_from_buf(buf_ptr, end, &verified_boot_state) &&
+ verified_boot_key.Deserialize(buf_ptr, end) &&
+ verified_boot_hash.Deserialize(buf_ptr, end);
+ }
+
+ uint32_t os_version;
+ uint32_t os_patchlevel;
+ uint32_t device_locked;
+ keymaster_verified_boot_t verified_boot_state;
+ Buffer verified_boot_key;
+ Buffer verified_boot_hash;
+};
+
+struct SetBootParamsResponse : public NoResponse {};
+
+struct SetAttestationKeyRequest : public KeymasterMessage {
+ explicit SetAttestationKeyRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override {
+ return sizeof(uint32_t) + key_data.SerializedSize();
+ }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ buf = append_uint32_to_buf(buf, end, algorithm);
+ return key_data.Serialize(buf, end);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+ key_data.Deserialize(buf_ptr, end);
+ }
+
+ keymaster_algorithm_t algorithm;
+ Buffer key_data;
+};
+
+struct SetAttestationKeyResponse : public NoResponse {};
+
+struct AppendAttestationCertChainRequest : public KeymasterMessage {
+ explicit AppendAttestationCertChainRequest(
+ int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override {
+ return sizeof(uint32_t) + cert_data.SerializedSize();
+ }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ buf = append_uint32_to_buf(buf, end, algorithm);
+ return cert_data.Serialize(buf, end);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+ cert_data.Deserialize(buf_ptr, end);
+ }
+
+ keymaster_algorithm_t algorithm;
+ Buffer cert_data;
+};
+
+struct AppendAttestationCertChainResponse : public NoResponse {};
+
+/**
+ * For Android Things Attestation Provisioning (ATAP), the GetCaRequest message
+ * in the protocol are raw opaque messages for the purposes of this IPC call.
+ * Since the SetCaResponse message will be very large (> 10k), SetCaResponse is
+ * split into *Begin, *Update, and *Finish operations.
+ */
+struct AtapGetCaRequestRequest : public RawBufferRequest {};
+struct AtapGetCaRequestResponse : public RawBufferResponse {};
+
+struct AtapSetCaResponseBeginRequest : public KeymasterMessage {
+ explicit AtapSetCaResponseBeginRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint32_t); }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ return append_uint32_to_buf(buf, end, ca_response_size);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &ca_response_size);
+ }
+
+ uint32_t ca_response_size;
+};
+struct AtapSetCaResponseBeginResponse : public NoResponse {};
+
+struct AtapSetCaResponseUpdateRequest : public RawBufferRequest {};
+struct AtapSetCaResponseUpdateResponse : public NoResponse {};
+
+struct AtapSetCaResponseFinishRequest : public NoRequest {};
+struct AtapSetCaResponseFinishResponse : public NoResponse {};
+struct AtapSetProductIdRequest : public RawBufferRequest {};
+struct AtapSetProductIdResponse : public NoResponse {};
+
+struct AtapReadUuidRequest : public NoRequest {};
+struct AtapReadUuidResponse : public RawBufferResponse {};
+
+} // namespace keymaster
+
+#endif // TRUSTY_APP_KEYMASTER_TRUSTY_KEYMASTER_MESSAGES_H_
diff --git a/include/amlogic_keymaster/ipc/amlogic_keymaster_ipc.h b/include/amlogic_keymaster/ipc/amlogic_keymaster_ipc.h
new file mode 100755
index 0000000..26d4001
--- a/dev/null
+++ b/include/amlogic_keymaster/ipc/amlogic_keymaster_ipc.h
@@ -0,0 +1,52 @@
+/*
+ * 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 TRUSTY_KEYMASTER_AMLOGIC_KEYMASTER_IPC_H_
+#define TRUSTY_KEYMASTER_AMLOGIC_KEYMASTER_IPC_H_
+
+#include <keymaster/android_keymaster_messages.h>
+#include <amlogic_keymaster/ipc/keymaster_ipc.h>
+
+extern "C" {
+#include <tee_client_api.h>
+}
+__BEGIN_DECLS
+
+const uint32_t AMLOGIC_KEYMASTER_RECV_BUF_SIZE = 2 * PAGE_SIZE;
+const uint32_t AMLOGIC_KEYMASTER_SEND_BUF_SIZE =
+ (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
+#if !AMLOGIC_MODIFY
+int trusty_keymaster_connect(void);
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size);
+void trusty_keymaster_disconnect(void);
+
+keymaster_error_t translate_error(int err);
+keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp);
+#else
+TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s);
+TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size);
+TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s);
+keymaster_error_t translate_error(int err);
+keymaster_error_t aml_keymaster_send(TEEC_Session *s, uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp);
+#endif
+
+__END_DECLS
+
+#endif // TRUSTY_KEYMASTER_AMLOGIC_KEYMASTER_IPC_H_
diff --git a/keymaster_ipc.h b/include/amlogic_keymaster/ipc/keymaster_ipc.h
index 1bbf2c7..9b6416d 100644..100755
--- a/keymaster_ipc.h
+++ b/include/amlogic_keymaster/ipc/keymaster_ipc.h
@@ -21,16 +21,17 @@
#define KEYMASTER_PORT "com.android.trusty.keymaster"
#define KEYMASTER_MAX_BUFFER_LENGTH 4096
+#if AMLOGIC_MODIFY
/* This UUID is generated with uuidgen
the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html */
#define TA_KEYMASTER_UUID {0x8efb1e1c, 0x37e5, 0x4326, \
{ 0xa5, 0xd6, 0x8c, 0x33, 0x72, 0x6c, 0x7d, 0x57} }
-
+#endif
// Commands
enum keymaster_command : uint32_t {
KEYMASTER_RESP_BIT = 1,
- KEYMASTER_STOP_BIT = 2,
- KEYMASTER_REQ_SHIFT = 2,
+ KEYMASTER_STOP_BIT = 2,
+ KEYMASTER_REQ_SHIFT = 2,
KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT),
KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT),
@@ -51,13 +52,21 @@ enum keymaster_command : uint32_t {
KM_ATTEST_KEY = (16 << KEYMASTER_REQ_SHIFT),
KM_UPGRADE_KEY = (17 << KEYMASTER_REQ_SHIFT),
KM_CONFIGURE = (18 << KEYMASTER_REQ_SHIFT),
-
+ KM_GET_HMAC_SHARING_PARAMETERS = (19 << KEYMASTER_REQ_SHIFT),
+ KM_COMPUTE_SHARED_HMAC = (20 << KEYMASTER_REQ_SHIFT),
+ KM_VERIFY_AUTHORIZATION = (21 << KEYMASTER_REQ_SHIFT),
+ KM_DELETE_KEY = (22 << KEYMASTER_REQ_SHIFT),
+ KM_DELETE_ALL_KEYS = (23 << KEYMASTER_REQ_SHIFT),
+ KM_DESTROY_ATTESTATION_IDS = (24 << KEYMASTER_REQ_SHIFT),
+ KM_IMPORT_WRAPPED_KEY = (25 << KEYMASTER_REQ_SHIFT),
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT),
KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT),
+#if AMLOGIC_MODIFY
KM_TA_INIT = (0x10000 << KEYMASTER_REQ_SHIFT),
KM_TA_TERM = (0x10001 << KEYMASTER_REQ_SHIFT),
+#endif
};
#ifdef __ANDROID__
diff --git a/ipc/amlogic_keymaster_ipc.cpp b/ipc/amlogic_keymaster_ipc.cpp
new file mode 100755
index 0000000..00e2d26
--- a/dev/null
+++ b/ipc/amlogic_keymaster_ipc.cpp
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AmlogicKeymaster"
+
+// TODO: make this generic in libtrusty
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <log/log.h>
+#if !AMLOGIC_MODIFY
+#include <trusty/tipc.h>
+#endif
+#include <amlogic_keymaster/ipc/keymaster_ipc.h>
+#include <amlogic_keymaster/ipc/amlogic_keymaster_ipc.h>
+
+#if AMLOGIC_MODIFY
+TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s) {
+ TEEC_Result result = TEEC_SUCCESS;
+ TEEC_UUID svc_id = TA_KEYMASTER_UUID;
+ TEEC_Operation operation;
+ uint32_t err_origin;
+ struct timespec time;
+ uint64_t millis = 0;
+
+ memset(&operation, 0, sizeof(operation));
+
+ /* Initialize Context */
+ result = TEEC_InitializeContext(NULL, c);
+
+ if (result != TEEC_SUCCESS) {
+ ALOGD("TEEC_InitializeContext failed with error = %x\n", result);
+ return result;
+ }
+ /* Open Session */
+ result = TEEC_OpenSession(c, s, &svc_id,
+ TEEC_LOGIN_PUBLIC,
+ NULL, NULL,
+ &err_origin);
+
+ if (result != TEEC_SUCCESS) {
+ ALOGD("TEEC_Opensession failed with code 0x%x origin 0x%x",result, err_origin);
+ TEEC_FinalizeContext(c);
+ return result;
+ }
+
+ int res = clock_gettime(CLOCK_BOOTTIME, &time);
+ if (res < 0)
+ millis = 0;
+ else
+ millis = (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+
+ /* Init TA */
+ operation.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_VALUE_INPUT, TEEC_NONE,
+ TEEC_NONE, TEEC_NONE);
+
+ operation.params[0].value.a = (millis >> 32);
+ operation.params[0].value.b = (millis & 0xffffffff);
+
+ result = TEEC_InvokeCommand(s,
+ KM_TA_INIT,
+ &operation,
+ NULL);
+
+ ALOGD("create id: %d, ctx: %p, ctx: %p\n", s->session_id, s->ctx, c);
+ return result;
+}
+
+TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size) {
+ TEEC_Result res = TEEC_SUCCESS;
+ TEEC_Operation op;
+ uint32_t ret_orig;
+
+ memset(&op, 0, sizeof(op));
+
+ op.params[0].tmpref.buffer = in;
+ op.params[0].tmpref.size = in_size;
+ op.params[1].tmpref.buffer = out;
+ op.params[1].tmpref.size = *out_size;
+ op.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_OUTPUT,
+ TEEC_VALUE_OUTPUT,
+ TEEC_NONE);
+
+ ALOGD("id: %d, ctx: %p, cmd: %d\n", s->session_id, s->ctx, cmd);
+ res = TEEC_InvokeCommand(s, cmd, &op, &ret_orig);
+ if (res != TEEC_SUCCESS) {
+ ALOGE("Invoke cmd: %u failed with res(%x), ret_orig(%x), return(%d)\n",
+ cmd, res, ret_orig, op.params[2].value.a);
+ } else {
+ *out_size = op.params[2].value.b;
+ }
+
+ return res;
+}
+
+TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s) {
+ TEEC_Operation operation;
+ TEEC_Result result = TEEC_SUCCESS;
+
+ operation.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_NONE, TEEC_NONE,
+ TEEC_NONE, TEEC_NONE);
+
+ result = TEEC_InvokeCommand(s,
+ KM_TA_TERM,
+ &operation,
+ NULL);
+
+ TEEC_CloseSession(s);
+ TEEC_FinalizeContext(c);
+
+ return result;
+}
+
+keymaster_error_t aml_keymaster_send(TEEC_Session *s, uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp) {
+ uint32_t req_size = req.SerializedSize();
+ if (req_size > AMLOGIC_KEYMASTER_SEND_BUF_SIZE) {
+ ALOGE("Request too big: %u Max size: %u", req_size, AMLOGIC_KEYMASTER_SEND_BUF_SIZE);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
+ uint8_t send_buf[AMLOGIC_KEYMASTER_SEND_BUF_SIZE];
+ keymaster::Eraser send_buf_eraser(send_buf, AMLOGIC_KEYMASTER_SEND_BUF_SIZE);
+ req.Serialize(send_buf, send_buf + req_size);
+
+ // Send it
+ uint8_t recv_buf[AMLOGIC_KEYMASTER_RECV_BUF_SIZE];
+ keymaster::Eraser recv_buf_eraser(recv_buf, AMLOGIC_KEYMASTER_RECV_BUF_SIZE);
+ uint32_t rsp_size = AMLOGIC_KEYMASTER_RECV_BUF_SIZE;
+ int rc = aml_keymaster_call(s, command, send_buf, req_size, recv_buf, &rsp_size);
+ if (rc < 0) {
+ ALOGE("tipc error: %d\n", rc);
+ // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+ return translate_error(rc);
+ } else {
+ ALOGD("Received %d byte response\n", rsp_size);
+ }
+
+ const keymaster_message* msg = (keymaster_message*)recv_buf;
+ const uint8_t* p = msg->payload;
+
+ if (!rsp->Deserialize(&p, p + rsp_size)) {
+ ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+ return KM_ERROR_UNKNOWN_ERROR;
+ } else if (rsp->error != KM_ERROR_OK) {
+ ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+ return rsp->error;
+ }
+ return rsp->error;
+}
+#else
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = -1;
+
+int trusty_keymaster_connect() {
+ int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+ if (rc < 0) {
+ return rc;
+ }
+
+ handle_ = rc;
+ return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size) {
+ if (handle_ < 0) {
+ ALOGE("not connected\n");
+ return -EINVAL;
+ }
+
+ size_t msg_size = in_size + sizeof(struct keymaster_message);
+ struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
+ if (!msg) {
+ ALOGE("failed to allocate msg buffer\n");
+ return -EINVAL;
+ }
+
+ msg->cmd = cmd;
+ memcpy(msg->payload, in, in_size);
+
+ ssize_t rc = write(handle_, msg, msg_size);
+ free(msg);
+
+ if (rc < 0) {
+ ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
+ return -errno;
+ }
+ size_t out_max_size = *out_size;
+ *out_size = 0;
+ struct iovec iov[2];
+ struct keymaster_message header;
+ iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
+ while (true) {
+ iov[1] = {.iov_base = out + *out_size,
+ .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH,
+ out_max_size - *out_size)};
+ rc = readv(handle_, iov, 2);
+ if (rc < 0) {
+ ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
+ strerror(errno));
+ return -errno;
+ }
+
+ if ((size_t)rc < sizeof(struct keymaster_message)) {
+ ALOGE("invalid response size (%d)\n", (int)rc);
+ return -EINVAL;
+ }
+
+ if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
+ ALOGE("invalid command (%d)", header.cmd);
+ return -EINVAL;
+ }
+ *out_size += ((size_t)rc - sizeof(struct keymaster_message));
+ if (header.cmd & KEYMASTER_STOP_BIT) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+void trusty_keymaster_disconnect() {
+ if (handle_ >= 0) {
+ tipc_close(handle_);
+ }
+ handle_ = -1;
+}
+
+#endif // AMLOGIC_MODIFY
+keymaster_error_t translate_error(int err) {
+ switch (err) {
+ case 0:
+ return KM_ERROR_OK;
+ case -EPERM:
+ case -EACCES:
+ return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+
+ case -ECANCELED:
+ return KM_ERROR_OPERATION_CANCELLED;
+
+ case -ENODEV:
+ return KM_ERROR_UNIMPLEMENTED;
+
+ case -ENOMEM:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ case -EBUSY:
+ return KM_ERROR_SECURE_HW_BUSY;
+
+ case -EIO:
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+
+ case -EOVERFLOW:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+#if !AMLOGIC_MODIFY
+keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
+ keymaster::KeymasterResponse* rsp) {
+ uint32_t req_size = req.SerializedSize();
+ if (req_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
+ ALOGE("Request too big: %u Max size: %u", req_size, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
+ uint8_t send_buf[TRUSTY_KEYMASTER_SEND_BUF_SIZE];
+ keymaster::Eraser send_buf_eraser(send_buf, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
+ req.Serialize(send_buf, send_buf + req_size);
+
+ // Send it
+ uint8_t recv_buf[TRUSTY_KEYMASTER_RECV_BUF_SIZE];
+ keymaster::Eraser recv_buf_eraser(recv_buf, TRUSTY_KEYMASTER_RECV_BUF_SIZE);
+ uint32_t rsp_size = TRUSTY_KEYMASTER_RECV_BUF_SIZE;
+ int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
+ if (rc < 0) {
+ // Reset the connection on tipc error
+ trusty_keymaster_disconnect();
+ trusty_keymaster_connect();
+ ALOGE("tipc error: %d\n", rc);
+ // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+ return translate_error(rc);
+ } else {
+ ALOGV("Received %d byte response\n", rsp_size);
+ }
+
+ const uint8_t* p = recv_buf;
+ if (!rsp->Deserialize(&p, p + rsp_size)) {
+ ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+ return KM_ERROR_UNKNOWN_ERROR;
+ } else if (rsp->error != KM_ERROR_OK) {
+ ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+ return rsp->error;
+ }
+ return rsp->error;
+}
+#endif //!AMLOGIC_MODIFY
diff --git a/module.cpp b/module.cpp
deleted file mode 100644
index b9ee918..0000000
--- a/module.cpp
+++ b/dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2014 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 <errno.h>
-#include <string.h>
-
-#include <hardware/hardware.h>
-#include <hardware/keymaster0.h>
-
-#include "aml_keymaster_device.h"
-
-using keymaster::AmlKeymasterDevice;
-
-/*
- * Generic device handling
- */
-static int aml_keymaster_open(const hw_module_t* module, const char* name, hw_device_t** device) {
- if (strcmp(name, KEYSTORE_KEYMASTER) != 0) {
- return -EINVAL;
- }
-
- AmlKeymasterDevice* dev = new AmlKeymasterDevice(module);
- if (dev == NULL) {
- return -ENOMEM;
- }
- *device = dev->hw_device();
- // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
- // exist until then.
- return 0;
-}
-
-static struct hw_module_methods_t keystore_module_methods = {
- .open = aml_keymaster_open,
-};
-
-struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
- .common =
- {
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = KEYSTORE_HARDWARE_MODULE_ID,
- .name = "Amlogic Keymaster HAL",
- .author = "Amlogic Inc.",
- .methods = &keystore_module_methods,
- .dso = 0,
- .reserved = {},
- },
-};
diff --git a/unit_test/android_keymaster_messages_test.cpp b/unit_test/android_keymaster_messages_test.cpp
deleted file mode 100644
index f7e65bc..0000000
--- a/unit_test/android_keymaster_messages_test.cpp
+++ b/dev/null
@@ -1,732 +0,0 @@
-/*
- * Copyright (C) 2014 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 <UniquePtr.h>
-
-#include <gtest/gtest.h>
-
-#include <keymaster/android_keymaster.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_tags.h>
-
-#include "android_keymaster_test_utils.h"
-
-namespace keymaster {
-namespace test {
-
-/**
- * Serialize and deserialize a message.
- */
-template <typename Message>
-Message* round_trip(int32_t ver, const Message& message, size_t expected_size) {
- size_t size = message.SerializedSize();
- EXPECT_EQ(expected_size, size);
- if (size == 0)
- return NULL;
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, message.Serialize(buf.get(), buf.get() + size));
-
- Message* deserialized = new Message(ver);
- const uint8_t* p = buf.get();
- EXPECT_TRUE(deserialized->Deserialize(&p, p + size));
- EXPECT_EQ((ptrdiff_t)size, p - buf.get());
- return deserialized;
-}
-
-struct EmptyKeymasterResponse : public KeymasterResponse {
- explicit EmptyKeymasterResponse(int32_t ver) : KeymasterResponse(ver) {}
- size_t NonErrorSerializedSize() const { return 1; }
- uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const {
- *buf++ = 0;
- return buf;
- }
- bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
- if (*buf_ptr >= end)
- return false;
- EXPECT_EQ(0, **buf_ptr);
- (*buf_ptr)++;
- return true;
- }
-};
-
-TEST(RoundTrip, EmptyKeymasterResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- EmptyKeymasterResponse msg(ver);
- msg.error = KM_ERROR_OK;
-
- UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 5));
- }
-}
-
-TEST(RoundTrip, EmptyKeymasterResponseError) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- EmptyKeymasterResponse msg(ver);
- msg.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 4));
- }
-}
-
-TEST(RoundTrip, SupportedByAlgorithmRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- SupportedByAlgorithmRequest req(ver);
- req.algorithm = KM_ALGORITHM_EC;
-
- UniquePtr<SupportedByAlgorithmRequest> deserialized(round_trip(ver, req, 4));
- EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
- }
-}
-
-TEST(RoundTrip, SupportedByAlgorithmAndPurposeRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- SupportedByAlgorithmAndPurposeRequest req(ver);
- req.algorithm = KM_ALGORITHM_EC;
- req.purpose = KM_PURPOSE_DECRYPT;
-
- UniquePtr<SupportedByAlgorithmAndPurposeRequest> deserialized(round_trip(ver, req, 8));
- EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
- EXPECT_EQ(KM_PURPOSE_DECRYPT, deserialized->purpose);
- }
-}
-
-TEST(RoundTrip, SupportedResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- SupportedResponse<keymaster_digest_t> rsp(ver);
- keymaster_digest_t digests[] = {KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1};
- rsp.error = KM_ERROR_OK;
- rsp.SetResults(digests);
-
- UniquePtr<SupportedResponse<keymaster_digest_t>> deserialized(round_trip(ver, rsp, 20));
- EXPECT_EQ(array_length(digests), deserialized->results_length);
- EXPECT_EQ(0, memcmp(deserialized->results, digests, array_size(digests)));
- }
-}
-
-static keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_USER_ID, 7),
- Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
- Authorization(TAG_APPLICATION_ID, "app_id", 6),
- Authorization(TAG_AUTH_TIMEOUT, 300),
-};
-uint8_t TEST_DATA[] = "a key blob";
-
-TEST(RoundTrip, GenerateKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- GenerateKeyRequest req(ver);
- req.key_description.Reinitialize(params, array_length(params));
- UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, 78));
- EXPECT_EQ(deserialized->key_description, req.key_description);
- }
-}
-
-TEST(RoundTrip, GenerateKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- GenerateKeyResponse rsp(ver);
- rsp.error = KM_ERROR_OK;
- rsp.key_blob.key_material = dup_array(TEST_DATA);
- rsp.key_blob.key_material_size = array_length(TEST_DATA);
- rsp.enforced.Reinitialize(params, array_length(params));
-
- UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 109));
- EXPECT_EQ(KM_ERROR_OK, deserialized->error);
- EXPECT_EQ(deserialized->enforced, rsp.enforced);
- EXPECT_EQ(deserialized->unenforced, rsp.unenforced);
- }
-}
-
-TEST(RoundTrip, GenerateKeyResponseTestError) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- GenerateKeyResponse rsp(ver);
- rsp.error = KM_ERROR_UNSUPPORTED_ALGORITHM;
- rsp.key_blob.key_material = dup_array(TEST_DATA);
- rsp.key_blob.key_material_size = array_length(TEST_DATA);
- rsp.enforced.Reinitialize(params, array_length(params));
-
- UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 4));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, deserialized->error);
- EXPECT_EQ(0U, deserialized->enforced.size());
- EXPECT_EQ(0U, deserialized->unenforced.size());
- EXPECT_EQ(0U, deserialized->key_blob.key_material_size);
- }
-}
-
-TEST(RoundTrip, GetKeyCharacteristicsRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- GetKeyCharacteristicsRequest req(ver);
- req.additional_params.Reinitialize(params, array_length(params));
- req.SetKeyMaterial("foo", 3);
-
- UniquePtr<GetKeyCharacteristicsRequest> deserialized(round_trip(ver, req, 85));
- EXPECT_EQ(7U, deserialized->additional_params.size());
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
- }
-}
-
-TEST(RoundTrip, GetKeyCharacteristicsResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- GetKeyCharacteristicsResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.enforced.Reinitialize(params, array_length(params));
- msg.unenforced.Reinitialize(params, array_length(params));
-
- UniquePtr<GetKeyCharacteristicsResponse> deserialized(round_trip(ver, msg, 160));
- EXPECT_EQ(msg.enforced, deserialized->enforced);
- EXPECT_EQ(msg.unenforced, deserialized->unenforced);
- }
-}
-
-TEST(RoundTrip, BeginOperationRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- BeginOperationRequest msg(ver);
- msg.purpose = KM_PURPOSE_SIGN;
- msg.SetKeyMaterial("foo", 3);
- msg.additional_params.Reinitialize(params, array_length(params));
-
- UniquePtr<BeginOperationRequest> deserialized(round_trip(ver, msg, 89));
- EXPECT_EQ(KM_PURPOSE_SIGN, deserialized->purpose);
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
- EXPECT_EQ(msg.additional_params, deserialized->additional_params);
- }
-}
-
-TEST(RoundTrip, BeginOperationResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- BeginOperationResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.op_handle = 0xDEADBEEF;
- msg.output_params.push_back(Authorization(TAG_NONCE, "foo", 3));
-
- UniquePtr<BeginOperationResponse> deserialized;
- switch (ver) {
- case 0:
- deserialized.reset(round_trip(ver, msg, 12));
- break;
- case 1:
- case 2:
- case 3:
- deserialized.reset(round_trip(ver, msg, 39));
- break;
- default:
- FAIL();
- }
-
- EXPECT_EQ(KM_ERROR_OK, deserialized->error);
- EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
-
- switch (ver) {
- case 0:
- EXPECT_EQ(0U, deserialized->output_params.size());
- break;
- case 1:
- case 2:
- case 3:
- EXPECT_EQ(msg.output_params, deserialized->output_params);
- break;
- default:
- FAIL();
- }
- }
-}
-
-TEST(RoundTrip, BeginOperationResponseError) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- BeginOperationResponse msg(ver);
- msg.error = KM_ERROR_INVALID_OPERATION_HANDLE;
- msg.op_handle = 0xDEADBEEF;
-
- UniquePtr<BeginOperationResponse> deserialized(round_trip(ver, msg, 4));
- EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, deserialized->error);
- }
-}
-
-TEST(RoundTrip, UpdateOperationRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- UpdateOperationRequest msg(ver);
- msg.op_handle = 0xDEADBEEF;
- msg.input.Reinitialize("foo", 3);
-
- UniquePtr<UpdateOperationRequest> deserialized;
- switch (ver) {
- case 0:
- deserialized.reset(round_trip(ver, msg, 15));
- break;
- case 1:
- case 2:
- case 3:
- deserialized.reset(round_trip(ver, msg, 27));
- break;
- default:
- FAIL();
- }
- EXPECT_EQ(3U, deserialized->input.available_read());
- EXPECT_EQ(0, memcmp(deserialized->input.peek_read(), "foo", 3));
- }
-}
-
-TEST(RoundTrip, UpdateOperationResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- UpdateOperationResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.output.Reinitialize("foo", 3);
- msg.input_consumed = 99;
- msg.output_params.push_back(TAG_APPLICATION_ID, "bar", 3);
-
- UniquePtr<UpdateOperationResponse> deserialized;
- switch (ver) {
- case 0:
- deserialized.reset(round_trip(ver, msg, 11));
- break;
- case 1:
- deserialized.reset(round_trip(ver, msg, 15));
- break;
- case 2:
- case 3:
- deserialized.reset(round_trip(ver, msg, 42));
- break;
- default:
- FAIL();
- }
- EXPECT_EQ(KM_ERROR_OK, deserialized->error);
- EXPECT_EQ(3U, deserialized->output.available_read());
- EXPECT_EQ(0, memcmp(deserialized->output.peek_read(), "foo", 3));
-
- switch (ver) {
- case 0:
- EXPECT_EQ(0U, deserialized->input_consumed);
- break;
- case 1:
- EXPECT_EQ(99U, deserialized->input_consumed);
- break;
- case 2:
- case 3:
- EXPECT_EQ(99U, deserialized->input_consumed);
- EXPECT_EQ(1U, deserialized->output_params.size());
- break;
- default:
- FAIL();
- }
- }
-}
-
-TEST(RoundTrip, FinishOperationRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- FinishOperationRequest msg(ver);
- msg.op_handle = 0xDEADBEEF;
- msg.signature.Reinitialize("bar", 3);
- msg.input.Reinitialize("baz", 3);
-
- UniquePtr<FinishOperationRequest> deserialized;
- switch (ver) {
- case 0:
- deserialized.reset(round_trip(ver, msg, 15));
- break;
- case 1:
- case 2:
- deserialized.reset(round_trip(ver, msg, 27));
- break;
- case 3:
- deserialized.reset(round_trip(ver, msg, 34));
- break;
- default:
- FAIL();
- }
- EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
- EXPECT_EQ(3U, deserialized->signature.available_read());
- EXPECT_EQ(0, memcmp(deserialized->signature.peek_read(), "bar", 3));
- }
-}
-
-TEST(Round_Trip, FinishOperationResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- FinishOperationResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.output.Reinitialize("foo", 3);
-
- UniquePtr<FinishOperationResponse> deserialized;
- switch (ver) {
- case 0:
- case 1:
- deserialized.reset(round_trip(ver, msg, 11));
- break;
- case 2:
- case 3:
- deserialized.reset(round_trip(ver, msg, 23));
- break;
- default:
- FAIL();
- }
- EXPECT_EQ(msg.error, deserialized->error);
- EXPECT_EQ(msg.output.available_read(), deserialized->output.available_read());
- EXPECT_EQ(0, memcmp(msg.output.peek_read(), deserialized->output.peek_read(),
- msg.output.available_read()));
- }
-}
-
-TEST(RoundTrip, ImportKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ImportKeyRequest msg(ver);
- msg.key_description.Reinitialize(params, array_length(params));
- msg.key_format = KM_KEY_FORMAT_X509;
- msg.SetKeyMaterial("foo", 3);
-
- UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, 89));
- EXPECT_EQ(msg.key_description, deserialized->key_description);
- EXPECT_EQ(msg.key_format, deserialized->key_format);
- EXPECT_EQ(msg.key_data_length, deserialized->key_data_length);
- EXPECT_EQ(0, memcmp(msg.key_data, deserialized->key_data, msg.key_data_length));
- }
-}
-
-TEST(RoundTrip, ImportKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ImportKeyResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.SetKeyMaterial("foo", 3);
- msg.enforced.Reinitialize(params, array_length(params));
- msg.unenforced.Reinitialize(params, array_length(params));
-
- UniquePtr<ImportKeyResponse> deserialized(round_trip(ver, msg, 167));
- EXPECT_EQ(msg.error, deserialized->error);
- EXPECT_EQ(msg.key_blob.key_material_size, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp(msg.key_blob.key_material, deserialized->key_blob.key_material,
- msg.key_blob.key_material_size));
- EXPECT_EQ(msg.enforced, deserialized->enforced);
- EXPECT_EQ(msg.unenforced, deserialized->unenforced);
- }
-}
-
-TEST(RoundTrip, ExportKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ExportKeyRequest msg(ver);
- msg.additional_params.Reinitialize(params, array_length(params));
- msg.key_format = KM_KEY_FORMAT_X509;
- msg.SetKeyMaterial("foo", 3);
-
- UniquePtr<ExportKeyRequest> deserialized(round_trip(ver, msg, 89));
- EXPECT_EQ(msg.additional_params, deserialized->additional_params);
- EXPECT_EQ(msg.key_format, deserialized->key_format);
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
- }
-}
-
-TEST(RoundTrip, ExportKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ExportKeyResponse msg(ver);
- msg.error = KM_ERROR_OK;
- msg.SetKeyMaterial("foo", 3);
-
- UniquePtr<ExportKeyResponse> deserialized(round_trip(ver, msg, 11));
- EXPECT_EQ(3U, deserialized->key_data_length);
- EXPECT_EQ(0, memcmp("foo", deserialized->key_data, 3));
- }
-}
-
-TEST(RoundTrip, DeleteKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- DeleteKeyRequest msg(ver);
- msg.SetKeyMaterial("foo", 3);
-
- UniquePtr<DeleteKeyRequest> deserialized(round_trip(ver, msg, 7));
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
- }
-}
-
-TEST(RoundTrip, DeleteKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- DeleteKeyResponse msg(ver);
- UniquePtr<DeleteKeyResponse> deserialized(round_trip(ver, msg, 4));
- }
-}
-
-TEST(RoundTrip, DeleteAllKeysRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- DeleteAllKeysRequest msg(ver);
- UniquePtr<DeleteAllKeysRequest> deserialized(round_trip(ver, msg, 0));
- }
-}
-
-TEST(RoundTrip, DeleteAllKeysResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- DeleteAllKeysResponse msg(ver);
- UniquePtr<DeleteAllKeysResponse> deserialized(round_trip(ver, msg, 4));
- }
-}
-
-TEST(RoundTrip, GetVersionRequest) {
- GetVersionRequest msg;
-
- size_t size = msg.SerializedSize();
- ASSERT_EQ(0U, size);
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
-
- GetVersionRequest deserialized;
- const uint8_t* p = buf.get();
- EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
- EXPECT_EQ((ptrdiff_t)size, p - buf.get());
-}
-
-TEST(RoundTrip, GetVersionResponse) {
- GetVersionResponse msg;
- msg.error = KM_ERROR_OK;
- msg.major_ver = 9;
- msg.minor_ver = 98;
- msg.subminor_ver = 38;
-
- size_t size = msg.SerializedSize();
- ASSERT_EQ(7U, size);
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
-
- GetVersionResponse deserialized;
- const uint8_t* p = buf.get();
- EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
- EXPECT_EQ((ptrdiff_t)size, p - buf.get());
- EXPECT_EQ(9U, msg.major_ver);
- EXPECT_EQ(98U, msg.minor_ver);
- EXPECT_EQ(38U, msg.subminor_ver);
-}
-
-TEST(RoundTrip, ConfigureRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ConfigureRequest req(ver);
- req.os_version = 1;
- req.os_patchlevel = 1;
-
- UniquePtr<ConfigureRequest> deserialized(round_trip(ver, req, 8));
- EXPECT_EQ(deserialized->os_version, req.os_version);
- EXPECT_EQ(deserialized->os_patchlevel, req.os_patchlevel);
- }
-}
-
-TEST(RoundTrip, ConfigureResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- ConfigureResponse rsp(ver);
- UniquePtr<ConfigureResponse> deserialized(round_trip(ver, rsp, 4));
- }
-}
-
-TEST(RoundTrip, AddEntropyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AddEntropyRequest msg(ver);
- msg.random_data.Reinitialize("foo", 3);
-
- UniquePtr<AddEntropyRequest> deserialized(round_trip(ver, msg, 7));
- EXPECT_EQ(3U, deserialized->random_data.available_read());
- EXPECT_EQ(0, memcmp("foo", deserialized->random_data.peek_read(), 3));
- }
-}
-
-TEST(RoundTrip, AddEntropyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AddEntropyResponse msg(ver);
- UniquePtr<AddEntropyResponse> deserialized(round_trip(ver, msg, 4));
- }
-}
-
-TEST(RoundTrip, AbortOperationRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AbortOperationRequest msg(ver);
- UniquePtr<AbortOperationRequest> deserialized(round_trip(ver, msg, 8));
- }
-}
-
-TEST(RoundTrip, AbortOperationResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AbortOperationResponse msg(ver);
- UniquePtr<AbortOperationResponse> deserialized(round_trip(ver, msg, 4));
- }
-}
-
-TEST(RoundTrip, AttestKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AttestKeyRequest msg(ver);
- msg.SetKeyMaterial("foo", 3);
- msg.attest_params.Reinitialize(params, array_length(params));
-
- UniquePtr<AttestKeyRequest> deserialized(round_trip(ver, msg, 85));
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
- EXPECT_EQ(msg.attest_params, deserialized->attest_params);
- }
-}
-
-TEST(RoundTrip, AttestKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- AttestKeyResponse msg(ver);
- msg.error = KM_ERROR_OK;
- EXPECT_TRUE(msg.AllocateChain(3));
- msg.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3};
- msg.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3};
- msg.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3};
-
- UniquePtr<AttestKeyResponse> deserialized(round_trip(ver, msg, 29));
- keymaster_cert_chain_t* chain = &deserialized->certificate_chain;
-
- EXPECT_NE(nullptr, chain->entries);
- EXPECT_EQ(3U, chain->entry_count);
- EXPECT_EQ(3U, chain->entries[0].data_length);
- EXPECT_EQ(0, memcmp("foo", chain->entries[0].data, 3));
- EXPECT_EQ(3U, chain->entries[1].data_length);
- EXPECT_EQ(0, memcmp("bar", chain->entries[1].data, 3));
- EXPECT_EQ(3U, chain->entries[2].data_length);
- EXPECT_EQ(0, memcmp("baz", chain->entries[2].data, 3));
- }
-}
-
-TEST(RoundTrip, UpgradeKeyRequest) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- UpgradeKeyRequest msg(ver);
- msg.SetKeyMaterial("foo", 3);
- msg.upgrade_params.Reinitialize(params, array_length(params));
-
- UniquePtr<UpgradeKeyRequest> deserialized(round_trip(ver, msg, 85));
- EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
- EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
- EXPECT_EQ(msg.upgrade_params, deserialized->upgrade_params);
- }
-}
-
-TEST(RoundTrip, UpgradeKeyResponse) {
- for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- UpgradeKeyResponse req(ver);
- req.error = KM_ERROR_OK;
- req.upgraded_key.key_material = dup_array(TEST_DATA);
- req.upgraded_key.key_material_size = array_length(TEST_DATA);
-
- UniquePtr<UpgradeKeyResponse> deserialized(round_trip(ver, req, 19));
- EXPECT_EQ(KM_ERROR_OK, deserialized->error);
- EXPECT_EQ(req.upgraded_key.key_material_size, deserialized->upgraded_key.key_material_size);
- EXPECT_EQ(0, memcmp(req.upgraded_key.key_material, deserialized->upgraded_key.key_material,
- req.upgraded_key.key_material_size));
- }
-}
-
-uint8_t msgbuf[] = {
- 220, 88, 183, 255, 71, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 173, 0, 0, 0, 228, 174, 98, 187, 191, 135, 253, 200, 51, 230, 114, 247, 151, 109,
- 237, 79, 87, 32, 94, 5, 204, 46, 154, 30, 91, 6, 103, 148, 254, 129, 65, 171, 228,
- 167, 224, 163, 9, 15, 206, 90, 58, 11, 205, 55, 211, 33, 87, 178, 149, 91, 28, 236,
- 218, 112, 231, 34, 82, 82, 134, 103, 137, 115, 27, 156, 102, 159, 220, 226, 89, 42, 25,
- 37, 9, 84, 239, 76, 161, 198, 72, 167, 163, 39, 91, 148, 191, 17, 191, 87, 169, 179,
- 136, 10, 194, 154, 4, 40, 107, 109, 61, 161, 20, 176, 247, 13, 214, 106, 229, 45, 17,
- 5, 60, 189, 64, 39, 166, 208, 14, 57, 25, 140, 148, 25, 177, 246, 189, 43, 181, 88,
- 204, 29, 126, 224, 100, 143, 93, 60, 57, 249, 55, 0, 87, 83, 227, 224, 166, 59, 214,
- 81, 144, 129, 58, 6, 57, 46, 254, 232, 41, 220, 209, 230, 167, 138, 158, 94, 180, 125,
- 247, 26, 162, 116, 238, 202, 187, 100, 65, 13, 180, 44, 245, 159, 83, 161, 176, 58, 72,
- 236, 109, 105, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 11, 0, 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0,
- 0, 32, 3, 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0,
- 1, 0, 0, 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112,
- 1, 246, 1, 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145,
- 1, 0, 96, 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0,
- 0, 0, 0, 0, 190, 2, 0, 16, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 11, 0,
- 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0, 0, 32, 3,
- 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0, 1, 0, 0,
- 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112, 1, 246, 1,
- 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145, 1, 0, 96,
- 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0, 0, 0, 0,
- 0, 190, 2, 0, 16, 1, 0, 0, 0,
-};
-
-/*
- * These tests don't have any assertions or expectations. They just try to parse garbage, to see if
- * the result will be a crash. This is especially informative when run under Valgrind memcheck.
- */
-
-template <typename Message> void parse_garbage() {
- for (int32_t ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
- Message msg(ver);
- const uint8_t* end = msgbuf + array_length(msgbuf);
- for (size_t i = 0; i < array_length(msgbuf); ++i) {
- const uint8_t* begin = msgbuf + i;
- const uint8_t* p = begin;
- msg.Deserialize(&p, end);
- }
- }
-
- time_t now = time(NULL);
- std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
- srand(now);
-
- // Fill large buffer with random bytes.
- const int kBufSize = 10000;
- UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
- for (size_t i = 0; i < kBufSize; ++i)
- buf[i] = static_cast<uint8_t>(rand());
-
- for (uint32_t ver = 0; ver < MAX_MESSAGE_VERSION; ++ver) {
- Message msg(ver);
- const uint8_t* end = buf.get() + kBufSize;
- for (size_t i = 0; i < kBufSize; ++i) {
- const uint8_t* begin = buf.get() + i;
- const uint8_t* p = begin;
- msg.Deserialize(&p, end);
- }
- }
-}
-#if 0
-#define GARBAGE_TEST(Message) \
- TEST(GarbageTest, Message) { parse_garbage<Message>(); }
-
-GARBAGE_TEST(AbortOperationRequest);
-GARBAGE_TEST(AbortOperationResponse);
-GARBAGE_TEST(AddEntropyRequest);
-GARBAGE_TEST(AddEntropyResponse);
-GARBAGE_TEST(BeginOperationRequest);
-GARBAGE_TEST(BeginOperationResponse);
-GARBAGE_TEST(DeleteAllKeysRequest);
-GARBAGE_TEST(DeleteAllKeysResponse);
-GARBAGE_TEST(DeleteKeyRequest);
-GARBAGE_TEST(DeleteKeyResponse);
-GARBAGE_TEST(ExportKeyRequest);
-GARBAGE_TEST(ExportKeyResponse);
-GARBAGE_TEST(FinishOperationRequest);
-GARBAGE_TEST(FinishOperationResponse);
-GARBAGE_TEST(GenerateKeyRequest);
-GARBAGE_TEST(GenerateKeyResponse);
-GARBAGE_TEST(GetKeyCharacteristicsRequest);
-GARBAGE_TEST(GetKeyCharacteristicsResponse);
-GARBAGE_TEST(ImportKeyRequest);
-GARBAGE_TEST(ImportKeyResponse);
-GARBAGE_TEST(SupportedByAlgorithmAndPurposeRequest)
-GARBAGE_TEST(SupportedByAlgorithmRequest)
-GARBAGE_TEST(UpdateOperationRequest);
-GARBAGE_TEST(UpdateOperationResponse);
-GARBAGE_TEST(AttestKeyRequest);
-GARBAGE_TEST(AttestKeyResponse);
-GARBAGE_TEST(UpgradeKeyRequest);
-GARBAGE_TEST(UpgradeKeyResponse);
-
-// The macro doesn't work on this one.
-TEST(GarbageTest, SupportedResponse) {
- parse_garbage<SupportedResponse<keymaster_digest_t>>();
-}
-#endif
-} // namespace test
-
-} // namespace keymaster
diff --git a/unit_test/android_keymaster_test.cpp b/unit_test/android_keymaster_test.cpp
deleted file mode 100644
index d11b5be..0000000
--- a/unit_test/android_keymaster_test.cpp
+++ b/dev/null
@@ -1,3976 +0,0 @@
-/*
- * Copyright (C) 2014 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 <fstream>
-#include <string>
-#include <vector>
-
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-#include <hardware/keymaster0.h>
-#include <keymaster/key_factory.h>
-#include <keymaster/soft_keymaster_context.h>
-#include <keymaster/soft_keymaster_device.h>
-#include <keymaster/softkeymaster.h>
-
-#include "android_keymaster_test_utils.h"
-#include "attestation_record.h"
-#include "keymaster0_engine.h"
-#include "openssl_utils.h"
-
-#define CHECK_FAIL 1
-#define SUPPORT_TEST 1
-#define RSA_TEST 1
-#define EC_TEST 1
-#define AES_TEST 1
-#define HMAC_TEST 1
-#define MAX_TEST 1
-#define ENTROPY_TEST 1
-#define ATTESTATIONTEST 1
-#define KEYUPGRADETEST 0
-using std::ifstream;
-using std::istreambuf_iterator;
-using std::ofstream;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-extern "C" {
-int __android_log_print(int prio, const char* tag, const char* fmt);
-int __android_log_print(int prio, const char* tag, const char* fmt) {
- (void)prio, (void)tag, (void)fmt;
- return 0;
-}
-} // extern "C"
-
-namespace keymaster {
-namespace test {
-
-const uint32_t kOsVersion = 060000;
-const uint32_t kOsPatchLevel = 201603;
-
-StdoutLogger logger;
-
-template <typename T> vector<T> make_vector(const T* array, size_t len) {
- return vector<T>(array, array + len);
-}
-
-/**
- * KeymasterEnforcement class for use in testing. It's permissive in the sense that it doesn't
- * check cryptoperiods, but restrictive in the sense that the clock never advances (so rate-limited
- * keys will only work once).
- */
-class TestKeymasterEnforcement : public KeymasterEnforcement {
- public:
- TestKeymasterEnforcement() : KeymasterEnforcement(3, 3) {}
-
- virtual bool activation_date_valid(uint64_t /* activation_date */) const { return true; }
- virtual bool expiration_date_passed(uint64_t /* expiration_date */) const { return false; }
- virtual bool auth_token_timed_out(const hw_auth_token_t& /* token */,
- uint32_t /* timeout */) const {
- return false;
- }
- virtual uint32_t get_current_time() const { return 0; }
- virtual bool ValidateTokenSignature(const hw_auth_token_t& /* token */) const { return true; }
-};
-
-/**
- * Variant of SoftKeymasterContext that provides a TestKeymasterEnforcement.
- */
-class TestKeymasterContext : public SoftKeymasterContext {
- public:
- TestKeymasterContext() {}
- explicit TestKeymasterContext(const string& root_of_trust) : SoftKeymasterContext(root_of_trust) {}
-
- KeymasterEnforcement* enforcement_policy() override { return &test_policy_; }
-
- private:
- TestKeymasterEnforcement test_policy_;
-};
-
-/**
- * Test instance creator that builds a pure software keymaster2 implementation.
- */
-class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator {
- public:
- keymaster2_device_t* CreateDevice() const override {
- std::cerr << "Creating software-only device" << std::endl;
- context_ = new TestKeymasterContext;
- SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, kOsVersion)
- .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
- device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
- return device->keymaster2_device();
- }
-
- bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
- int keymaster0_calls() const override { return 0; }
- bool is_keymaster1_hw() const override { return false; }
- KeymasterContext* keymaster_context() const override { return context_; }
-
- private:
- mutable TestKeymasterContext* context_;
-};
-
-/**
- * Test instance creator that builds a keymaster2 implementations.
- */
-class AmlKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator {
- public:
- keymaster2_device_t* CreateDevice() const override {
- const hw_module_t* mod;
- keymaster2_device_t* device = NULL;
-
- int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
- if (rc) {
- std::cerr << "Could not find any keystore module!" << std::endl;
- } else {
- assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0);
- rc = keymaster2_open(mod, &device);
- if (rc) {
- std::cerr << "Error "<< rc << "opening keystore keymaster2 device" << std::endl;
- return NULL;
- }
- }
-
- std::cerr << "Creating Amlogic keymaster2 device" << std::endl;
- // context_ = new TestKeymasterContext;
- // SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, kOsVersion)
- .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
- device->configure(device, &version_info);
- _device = device;
- return device;
- }
-
- bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
- int keymaster0_calls() const override { return 0; }
- bool is_keymaster1_hw() const override { return false; }
- KeymasterContext* keymaster_context() const override { return (KeymasterContext*) _device; }
-
- private:
- static keymaster2_device_t* _device;
- //mutable TestKeymasterContext* context_;
-};
-
-keymaster2_device_t* AmlKeymasterTestInstanceCreator::_device;
-/**
- * Test instance creator that builds keymaster1 instances which wrap a faked hardware keymaster0
- * instance, with or without EC support.
- */
-class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreator {
- public:
- explicit Keymaster0AdapterTestInstanceCreator(bool support_ec) : support_ec_(support_ec) {}
-
- keymaster2_device_t* CreateDevice() const {
- std::cerr << "Creating keymaster0-backed device (with ec: " << std::boolalpha << support_ec_
- << ")." << std::endl;
- hw_device_t* softkeymaster_device;
- EXPECT_EQ(0, openssl_open(&softkeymaster_module.common, KEYSTORE_KEYMASTER,
- &softkeymaster_device));
- // Make the software device pretend to be hardware
- keymaster0_device_t* keymaster0_device =
- reinterpret_cast<keymaster0_device_t*>(softkeymaster_device);
- keymaster0_device->flags &= ~KEYMASTER_SOFTWARE_ONLY;
-
- if (!support_ec_) {
- // Make the software device pretend not to support EC
- keymaster0_device->flags &= ~KEYMASTER_SUPPORTS_EC;
- }
-
- counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device);
-
- context_ = new TestKeymasterContext;
- SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(context_);
- keymaster->SetHardwareDevice(counting_keymaster0_device_);
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, kOsVersion)
- .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
- keymaster->keymaster2_device()->configure(keymaster->keymaster2_device(), &version_info);
- return keymaster->keymaster2_device();
- }
-
- bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const override {
- switch (algorithm) {
- case KM_ALGORITHM_RSA:
- return true;
- case KM_ALGORITHM_EC:
- return support_ec_;
- default:
- return false;
- }
- }
- int keymaster0_calls() const override { return counting_keymaster0_device_->count(); }
- bool is_keymaster1_hw() const override { return false; }
- KeymasterContext* keymaster_context() const override { return context_; }
-
- private:
- mutable TestKeymasterContext* context_;
- mutable Keymaster0CountingWrapper* counting_keymaster0_device_;
- bool support_ec_;
-};
-
-/**
- * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1
- * instance, with minimal digest support.
- */
-class Sha256OnlyKeymaster2TestInstanceCreator : public Keymaster2TestInstanceCreator {
- keymaster2_device_t* CreateDevice() const {
- std::cerr << "Creating keymaster1-backed device that supports only SHA256";
-
- // fake_device doesn't leak because device (below) takes ownership of it.
- keymaster1_device_t* fake_device = make_device_sha256_only(
- (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device());
-
- // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
- context_ = new TestKeymasterContext;
- SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
- device->SetHardwareDevice(fake_device);
-
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, kOsVersion)
- .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
- device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
- return device->keymaster2_device();
- }
-
- bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
- int keymaster0_calls() const override { return 0; }
- int minimal_digest_set() const override { return true; }
- bool is_keymaster1_hw() const override { return true; }
- KeymasterContext* keymaster_context() const override { return context_; }
-
- private:
- mutable TestKeymasterContext* context_;
-};
-
-static auto test_params = testing::Values(
-#if 0
- InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
- InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
- InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)),
- InstanceCreatorPtr(new Sha256OnlyKeymaster2TestInstanceCreator)
-#endif
- InstanceCreatorPtr(new AmlKeymasterTestInstanceCreator)
- );
-
-class NewKeyGeneration : public Keymaster2Test {
- protected:
- void CheckBaseParams() {
- AuthorizationSet auths = sw_enforced();
- auths.Union(hw_enforced());
- EXPECT_GT(auths.SerializedSize(), 12U);
-
- EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
- EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
- EXPECT_TRUE(contains(auths, TAG_USER_ID, 7));
- EXPECT_TRUE(contains(auths, TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
- EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300));
-
- // Verify that App ID, App data and ROT are NOT included.
- EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST));
- EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID));
- EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA));
-
- // Just for giggles, check that some unexpected tags/values are NOT present.
- EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
- EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
- EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301));
-
- // Now check that unspecified, defaulted tags are correct.
- EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
- if (GetParam()->is_keymaster1_hw()) {
- // If the underlying (faked) HW is KM1, it will not have version info.
- EXPECT_FALSE(auths.Contains(TAG_OS_VERSION));
- EXPECT_FALSE(auths.Contains(TAG_OS_PATCHLEVEL));
- } else {
- // In all othe cases; SoftKeymasterDevice keys, or keymaster0 keys wrapped by
- // SoftKeymasterDevice, version information will be present and up to date.
- EXPECT_TRUE(contains(auths, TAG_OS_VERSION, kOsVersion));
- EXPECT_TRUE(contains(auths, TAG_OS_PATCHLEVEL, kOsPatchLevel));
- }
- }
-};
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params);
-#if RSA_TEST
-TEST_P(NewKeyGeneration, Rsa) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- CheckBaseParams();
-
- // Check specified tags are all present, and in the right set.
- AuthorizationSet crypto_params;
- AuthorizationSet non_crypto_params;
-#if 0
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
- EXPECT_NE(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(hw_enforced());
- non_crypto_params.push_back(sw_enforced());
- } else {
- EXPECT_EQ(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(sw_enforced());
- }
-#else
- EXPECT_NE(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(hw_enforced());
- non_crypto_params.push_back(sw_enforced());
-#endif
-
- EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 256));
- EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 256));
- EXPECT_TRUE(contains(crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
- EXPECT_FALSE(contains(non_crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
-
- EXPECT_EQ(KM_ERROR_OK, DeleteKey());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(NewKeyGeneration, RsaDefaultSize) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
- .SigningKey()));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(NewKeyGeneration, Ecdsa) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
- CheckBaseParams();
-
- // Check specified tags are all present, and in the right set.
- AuthorizationSet crypto_params;
- AuthorizationSet non_crypto_params;
-#if 0
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
- EXPECT_NE(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(hw_enforced());
- non_crypto_params.push_back(sw_enforced());
- } else {
- EXPECT_EQ(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(sw_enforced());
- }
-#else
- EXPECT_NE(0U, hw_enforced().size());
- EXPECT_NE(0U, sw_enforced().size());
- crypto_params.push_back(hw_enforced());
- non_crypto_params.push_back(sw_enforced());
-#endif
-
- EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
- EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
- EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 224));
- EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 224));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(1, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(NewKeyGeneration, EcdsaDefaultSize) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
- GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
- .SigningKey()
- .Digest(KM_DIGEST_NONE)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, EcdsaInvalidSize) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if EC_TEST
-TEST_P(NewKeyGeneration, EcdsaMismatchKeySize) {
- ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT,
- GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(224)
- .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256)
- .Digest(KM_DIGEST_NONE)));
-}
-#endif
-
-#if EC_TEST
-TEST_P(NewKeyGeneration, EcdsaAllValidSizes) {
- size_t valid_sizes[] = {224, 256, 384, 521};
- for (size_t size : valid_sizes) {
- EXPECT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(
- KM_DIGEST_NONE)))
- << "Failed to generate size: " << size;
- }
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(NewKeyGeneration, HmacSha256) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 256)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, HmacMultipleDigests) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA1)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, HmacDigestNone) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 48)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 130)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) {
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 384)));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test GetKeyCharacteristics;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, GetKeyCharacteristics, test_params);
-
-#if RSA_TEST
-TEST_P(GetKeyCharacteristics, SimpleRsa) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- AuthorizationSet original(sw_enforced());
-
- ASSERT_EQ(KM_ERROR_OK, GetCharacteristics());
- EXPECT_EQ(original, sw_enforced());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(1, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test SigningOperationsTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, SigningOperationsTest, test_params);
-#if RSA_TEST
-TEST_P(SigningOperationsTest, RsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string message = "12345678901234567890123456789012";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(SigningOperationsTest, RsaPssSha256Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(768, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PSS)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string message = "12345678901234567890123456789012";
- string signature;
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- string message(53, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLarge) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- string message(54, 'a');
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- string signature;
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&signature));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if CHECK_FAIL
-TEST_P(SigningOperationsTest, RsaPssSha256TooSmallKey) {
- // Key must be at least 10 bytes larger than hash, to provide eight bytes of random salt, so
- // verify that nine bytes larger than hash won't work.
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256 + 9 * 8, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PSS)));
- string message(1024, 'a');
- string signature;
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-}
-#endif
-#if CHECK_FAIL
-TEST_P(SigningOperationsTest, RsaNoPaddingHugeData) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- string message(64 * 1024, 'a');
- string signature;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
- ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if CHECK_FAIL
-TEST_P(SigningOperationsTest, RsaAbort) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- EXPECT_EQ(KM_ERROR_OK, AbortOperation());
- // Another abort should fail
- EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, AbortOperation());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_SHA_2_256 /* supported digest */)
- .Padding(KM_PAD_PKCS7));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaNoDigest) {
- // PSS requires a digest.
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_RSA_PSS));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
- ASSERT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaNoPadding) {
- // Padding must be specified
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaKey(256, 3).SigningKey().Digest(
- KM_DIGEST_NONE)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaTooShortMessage) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string message = "1234567890123456789012345678901";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string message(256 / 8, static_cast<char>(0xff));
- string signature;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- string result;
- size_t input_consumed;
- ASSERT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- ASSERT_EQ(message.size(), input_consumed);
- string output;
- ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&output));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(SigningOperationsTest, EcdsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
- string message(224 / 8, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(SigningOperationsTest, EcdsaSha256Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
- KM_DIGEST_SHA_2_256)));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, EcdsaSha384Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
- KM_DIGEST_SHA_2_384)));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_384);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, EcdsaNoPaddingHugeData) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
- string message(64 * 1024, 'a');
- string signature;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
- vector<int> key_sizes = {224, 256, 384, 521};
- vector<keymaster_digest_t> digests = {
- KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
- KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
- };
-
- for (int key_size : key_sizes) {
- for (keymaster_digest_t digest : digests) {
- ASSERT_EQ(
- KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(digest)));
-
- string message(1024, 'a');
- string signature;
- if (digest == KM_DIGEST_NONE)
- message.resize(key_size / 8);
- SignMessage(message, &signature, digest);
- }
- }
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(digests.size() * key_sizes.size() * 3,
- static_cast<size_t>(GetParam()->keymaster0_calls()));
-}
-#endif
-#if AES_TEST
-TEST_P(SigningOperationsTest, AesEcbSign) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128).Authorization(
- TAG_BLOCK_MODE, KM_MODE_ECB)));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_SIGN));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_VERIFY));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(SigningOperationsTest, HmacSha1Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate other digests for HMAC.
- return;
-
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA1)
- .Authorization(TAG_MIN_MAC_LENGTH, 160));
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 160);
- ASSERT_EQ(20U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(SigningOperationsTest, HmacSha224Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate other digests for HMAC.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_224)
- .Authorization(TAG_MIN_MAC_LENGTH, 160)));
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 224);
- ASSERT_EQ(28U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacSha256Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate other digests for HMAC.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 256)));
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 256);
- ASSERT_EQ(32U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacSha384Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate other digests for HMAC.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_384)
- .Authorization(TAG_MIN_MAC_LENGTH, 384)));
-
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 384);
- ASSERT_EQ(48U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacSha512Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate other digests for HMAC.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_512)
- .Authorization(TAG_MIN_MAC_LENGTH, 384)));
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 512);
- ASSERT_EQ(64U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacLengthInKey) {
- // TODO(swillden): unified API should generate an error on key generation.
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string message = "12345678901234567890123456789012";
- string signature;
- MacMessage(message, &signature, 160);
- ASSERT_EQ(20U, signature.size());
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase1) {
- uint8_t key_data[] = {
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- };
- string message = "Hi There";
- uint8_t sha_224_expected[] = {
- 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d,
- 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22,
- };
- uint8_t sha_256_expected[] = {
- 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf,
- 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83,
- 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
- };
- uint8_t sha_384_expected[] = {
- 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4,
- 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
- 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9,
- 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6,
- };
- uint8_t sha_512_expected[] = {
- 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, 0x1a,
- 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0,
- 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7,
- 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e,
- 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54,
- };
-
- string key = make_string(key_data);
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase2) {
- string key = "Jefe";
- string message = "what do ya want for nothing?";
- uint8_t sha_224_expected[] = {
- 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e,
- 0x6d, 0x0f, 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, 0x8f, 0xd0, 0x5e, 0x44,
- };
- uint8_t sha_256_expected[] = {
- 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24,
- 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27,
- 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
- };
- uint8_t sha_384_expected[] = {
- 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2,
- 0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
- 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca,
- 0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49,
- };
- uint8_t sha_512_expected[] = {
- 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b,
- 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 0x10, 0x27,
- 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99,
- 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, 0xca, 0xea, 0xb1, 0xa3,
- 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
- string key(20, 0xaa);
- string message(50, 0xdd);
- uint8_t sha_224_expected[] = {
- 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
- 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
- };
- uint8_t sha_256_expected[] = {
- 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
- 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
- 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
- };
- uint8_t sha_384_expected[] = {
- 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
- 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
- 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
- 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
- };
- uint8_t sha_512_expected[] = {
- 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
- 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
- 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
- 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
- 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase4) {
- uint8_t key_data[25] = {
- 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,
- };
- string key = make_string(key_data);
- string message(50, 0xcd);
- uint8_t sha_224_expected[] = {
- 0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac, 0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82,
- 0x62, 0x7c, 0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d, 0xe7, 0xaf, 0xec, 0x5a,
- };
- uint8_t sha_256_expected[] = {
- 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81,
- 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78,
- 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b,
- };
- uint8_t sha_384_expected[] = {
- 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62,
- 0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
- 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23,
- 0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb,
- };
- uint8_t sha_512_expected[] = {
- 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, 0xf6,
- 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 0xe7, 0x6f,
- 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e,
- 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, 0xa5, 0xf1, 0x97, 0x41,
- 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
- string key(20, 0x0c);
- string message = "Test With Truncation";
-
- uint8_t sha_224_expected[] = {
- 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
- 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
- };
- uint8_t sha_256_expected[] = {
- 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
- 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
- };
- uint8_t sha_384_expected[] = {
- 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
- 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
- };
- uint8_t sha_512_expected[] = {
- 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
- 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if HMAC_TEST
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) {
- string key(131, 0xaa);
- string message = "Test Using Larger Than Block-Size Key - Hash Key First";
-
- uint8_t sha_224_expected[] = {
- 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
- 0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
- };
- uint8_t sha_256_expected[] = {
- 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
- 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
- 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
- };
- uint8_t sha_384_expected[] = {
- 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
- 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
- 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
- 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
- };
- uint8_t sha_512_expected[] = {
- 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
- 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
- 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
- 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
- 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if HMAC_TEST
-TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) {
- string key(131, 0xaa);
- string message = "This is a test using a larger than block-size key and a larger than "
- "block-size data. The key needs to be hashed before being used by the HMAC "
- "algorithm.";
-
- uint8_t sha_224_expected[] = {
- 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
- 0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
- };
- uint8_t sha_256_expected[] = {
- 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
- 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
- 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
- };
- uint8_t sha_384_expected[] = {
- 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
- 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
- 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
- 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
- };
- uint8_t sha_512_expected[] = {
- 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
- 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
- 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
- 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
- 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
- };
-
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
- if (!GetParam()->minimal_digest_set()) {
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
- CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 256)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_MAC_LENGTH, 264);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
- BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_MAC_LENGTH, 120);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- ASSERT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
- BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-// TODO(swillden): Add more verification failure tests.
-
-typedef Keymaster2Test VerificationOperationsTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, VerificationOperationsTest, test_params);
-#if RSA_TEST
-TEST_P(VerificationOperationsTest, RsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string message = "12345678901234567890123456789012";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPssSha256Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(768, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PSS)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPssSha224Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_224)
- .Padding(KM_PAD_RSA_PSS)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
- // Verify with OpenSSL.
- string pubkey;
- EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
-
- const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
- unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
- ASSERT_TRUE(pkey.get());
-
- EVP_MD_CTX digest_ctx;
- EVP_MD_CTX_init(&digest_ctx);
- EVP_PKEY_CTX* pkey_ctx;
- EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
- pkey.get()));
- EXPECT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
- EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
- EXPECT_EQ(1,
- EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
- signature.size()));
- EVP_MD_CTX_cleanup(&digest_ctx);
-}
-
-TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(768, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PSS));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
- ++signature[signature.size() / 2];
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(768, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PSS)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
- ++message[message.size() / 2];
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPkcs1Sha256Success) {
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPks1Sha224Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_224)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
- // Verify with OpenSSL.
- string pubkey;
- EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
-
- const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
- unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
- ASSERT_TRUE(pkey.get());
-
- EVP_MD_CTX digest_ctx;
- EVP_MD_CTX_init(&digest_ctx);
- EVP_PKEY_CTX* pkey_ctx;
- EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
- pkey.get()));
- EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
- EXPECT_EQ(1,
- EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
- signature.size()));
- EVP_MD_CTX_cleanup(&digest_ctx);
-}
-
-TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptSignature) {
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
- ++signature[signature.size() / 2];
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
- // Use large message, which won't work without digesting.
- string message(1024, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
- ++message[message.size() / 2];
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if CHECK_FAIL
-TEST_P(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
- vector<keymaster_digest_t> digests = {
- KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
- KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
- };
-
- vector<keymaster_padding_t> padding_modes{
- KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
- };
-
- int trial_count = 0;
- for (keymaster_padding_t padding_mode : padding_modes) {
- for (keymaster_digest_t digest : digests) {
- if (digest != KM_DIGEST_NONE && padding_mode == KM_PAD_NONE)
- // Digesting requires padding
- continue;
-
- // Compute key & message size that will work.
- size_t key_bits = 0;
- size_t message_len = 1000;
-
- if (digest == KM_DIGEST_NONE) {
- key_bits = 256;
- switch (padding_mode) {
- case KM_PAD_NONE:
- // Match key size.
- message_len = key_bits / 8;
- break;
- case KM_PAD_RSA_PKCS1_1_5_SIGN:
- message_len = key_bits / 8 - 11;
- break;
- case KM_PAD_RSA_PSS:
- // PSS requires a digest.
- continue;
- default:
- FAIL() << "Missing padding";
- break;
- }
- } else {
- size_t digest_bits;
- switch (digest) {
- case KM_DIGEST_MD5:
- digest_bits = 128;
- break;
- case KM_DIGEST_SHA1:
- digest_bits = 160;
- break;
- case KM_DIGEST_SHA_2_224:
- digest_bits = 224;
- break;
- case KM_DIGEST_SHA_2_256:
- digest_bits = 256;
- break;
- case KM_DIGEST_SHA_2_384:
- digest_bits = 384;
- break;
- case KM_DIGEST_SHA_2_512:
- digest_bits = 512;
- break;
- default:
- FAIL() << "Missing digest";
- }
-
- switch (padding_mode) {
- case KM_PAD_RSA_PKCS1_1_5_SIGN:
- key_bits = digest_bits + 8 * (11 + 19);
- break;
- case KM_PAD_RSA_PSS:
- key_bits = digest_bits * 2 + 2 * 8;
- break;
- default:
- FAIL() << "Missing padding";
- break;
- }
- }
-
- // round up to 128 bits because new boringssl supports only 128 bit mulitples
- key_bits += 127;
- key_bits &= ~127;
- GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(key_bits, 3)
- .Digest(digest)
- .Padding(padding_mode));
- string message(message_len, 'a');
- string signature;
- SignMessage(message, &signature, digest, padding_mode);
- VerifyMessage(message, signature, digest, padding_mode);
- ++trial_count;
- }
- }
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(trial_count * 4, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(VerificationOperationsTest, EcdsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
- string message = "12345678901234567890123456789012";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, EcdsaTooShort) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
- string message = "12345678901234567890";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, EcdsaSlightlyTooLong) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(521).Digest(KM_DIGEST_NONE)));
-
- string message(66, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- // Modifying low-order bits doesn't matter, because they didn't get signed. Ugh.
- message[65] ^= 7;
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(5, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, EcdsaSha256Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(256)
- .Digest(KM_DIGEST_SHA_2_256)
- .Digest(KM_DIGEST_NONE)));
- string message = "12345678901234567890123456789012";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
- // Just for giggles, try verifying with the wrong digest.
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-}
-
-TEST_P(VerificationOperationsTest, EcdsaSha224Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
- KM_DIGEST_SHA_2_224)));
-
- string message = "12345678901234567890123456789012";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_224);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_224);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
- // Just for giggles, try verifying with the wrong digest.
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
-}
-
-TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndKeySizes) {
- keymaster_digest_t digests[] = {
- KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
- KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
- };
- size_t key_sizes[] = {224, 256, 384, 521};
-
- string message = "1234567890";
- string signature;
-
- for (auto key_size : key_sizes) {
- AuthorizationSetBuilder builder;
- builder.EcdsaSigningKey(key_size);
- for (auto digest : digests)
- builder.Digest(digest);
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(builder));
-
- for (auto digest : digests) {
- SignMessage(message, &signature, digest);
- VerifyMessage(message, signature, digest);
- }
- }
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(static_cast<int>(array_length(key_sizes) * (1 + 3 * array_length(digests))),
- GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(VerificationOperationsTest, HmacSha1Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate missing digests for HMAC.
- return;
-
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA1)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 160);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, HmacSha224Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate missing digests for HMAC.
- return;
-
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_224)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 224);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, HmacSha256Success) {
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 256);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) {
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 256);
-
- // Shorten to 128 bits, should still work.
- signature.resize(128 / 8);
- VerifyMac(message, signature);
-
- // Drop one more byte.
- signature.resize(signature.length() - 1);
-
- AuthorizationSet begin_params(client_params());
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(signature, &result));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, HmacSha384Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate missing digests for HMAC.
- return;
-
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_384)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 384);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(VerificationOperationsTest, HmacSha512Success) {
- if (GetParam()->minimal_digest_set())
- // Can't emulate missing digests for HMAC.
- return;
-
- GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_512)
- .Authorization(TAG_MIN_MAC_LENGTH, 128));
- string message = "123456789012345678901234567890123456789012345678";
- string signature;
- MacMessage(message, &signature, 512);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test ExportKeyTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ExportKeyTest, test_params);
-#if RSA_TEST
-TEST_P(ExportKeyTest, RsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string export_data;
- ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
- EXPECT_GT(export_data.length(), 0U);
-
- // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(ExportKeyTest, EcdsaSuccess) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
- string export_data;
- ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
- EXPECT_GT(export_data.length(), 0U);
-
- // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- string export_data;
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
- corrupt_key_blob();
- string export_data;
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, ExportKey(KM_KEY_FORMAT_X509, &export_data));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(ExportKeyTest, AesKeyExportFails) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128)));
- string export_data;
-
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_X509, &export_data));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_RAW, &export_data));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-static string read_file(const string& file_name) {
- ifstream file_stream(file_name, std::ios::binary);
- istreambuf_iterator<char> file_begin(file_stream);
- istreambuf_iterator<char> file_end;
- return string(file_begin, file_end);
-}
-
-typedef Keymaster2Test ImportKeyTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ImportKeyTest, test_params);
-#if RSA_TEST
-TEST_P(ImportKeyTest, RsaSuccess) {
- string pk8_key = read_file("rsa_privkey_pk8.der");
- ASSERT_EQ(633U, pk8_key.size());
-
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .RsaSigningKey(1024, 65537)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- // Check values derived from the key.
- EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 1024));
- EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 65537U));
-
- // And values provided by AndroidKeymaster
- EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
- EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
-
- string message(1024 / 8, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
- string pk8_key = read_file("rsa_privkey_pk8.der");
- ASSERT_EQ(633U, pk8_key.size());
- ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
- ImportKey(AuthorizationSetBuilder()
- .RsaSigningKey(2048 /* Doesn't match key */, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(ImportKeyTest, RsaPublicExponenMismatch) {
- string pk8_key = read_file("rsa_privkey_pk8.der");
- ASSERT_EQ(633U, pk8_key.size());
- ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
- ImportKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3 /* Doesnt' match key */)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(ImportKeyTest, EcdsaSuccess) {
- string pk8_key = read_file("ec_privkey_pk8.der");
- ASSERT_EQ(138U, pk8_key.size());
-
- ASSERT_EQ(KM_ERROR_OK,
- ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- // Check values derived from the key.
- EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC));
- EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 256));
-
- // And values provided by AndroidKeymaster
- EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
- EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
-
- string message(32, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(ImportKeyTest, EcdsaSizeSpecified) {
- string pk8_key = read_file("ec_privkey_pk8.der");
- ASSERT_EQ(138U, pk8_key.size());
-
- ASSERT_EQ(KM_ERROR_OK,
- ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- // Check values derived from the key.
- EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC));
- EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 256));
-
- // And values provided by AndroidKeymaster
- EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
- EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
-
- string message(32, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
- string pk8_key = read_file("ec_privkey_pk8.der");
- ASSERT_EQ(138U, pk8_key.size());
- ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
- ImportKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(224 /* Doesn't match key */)
- .Digest(KM_DIGEST_NONE),
- KM_KEY_FORMAT_PKCS8, pk8_key));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(ImportKeyTest, AesKeySuccess) {
- char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- string key(key_data, sizeof(key_data));
- ASSERT_EQ(KM_ERROR_OK,
- ImportKey(AuthorizationSetBuilder().AesEncryptionKey(128).EcbMode().Authorization(
- TAG_PADDING, KM_PAD_PKCS7),
- KM_KEY_FORMAT_RAW, key));
-
- EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
- EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
-
- string message = "Hello World!";
- string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
- string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(ImportKeyTest, HmacSha256KeySuccess) {
- char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- string key(key_data, sizeof(key_data));
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .HmacKey(sizeof(key_data) * 8)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(TAG_MIN_MAC_LENGTH, 256),
- KM_KEY_FORMAT_RAW, key));
-
- EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
- EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
-
- string message = "Hello World!";
- string signature;
- MacMessage(message, &signature, 256);
- VerifyMac(message, signature);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test EncryptionOperationsTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, EncryptionOperationsTest, test_params);
-#if RSA_TEST
-TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
-
- string message = "12345678901234567890123456789012";
- string ciphertext1 = EncryptMessage(string(message), KM_PAD_NONE);
- EXPECT_EQ(256U / 8, ciphertext1.size());
-
- string ciphertext2 = EncryptMessage(string(message), KM_PAD_NONE);
- EXPECT_EQ(256U / 8, ciphertext2.size());
-
- // Unpadded RSA is deterministic
- EXPECT_EQ(ciphertext1, ciphertext2);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaNoPaddingTooShort) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
-
- string message = "1";
-
- string ciphertext = EncryptMessage(message, KM_PAD_NONE);
- EXPECT_EQ(256U / 8, ciphertext.size());
-
- string expected_plaintext = string(256 / 8 - 1, 0) + message;
- string plaintext = DecryptMessage(ciphertext, KM_PAD_NONE);
-
- EXPECT_EQ(expected_plaintext, plaintext);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
-
- string message = "123456789012345678901234567890123";
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaNoPaddingLargerThanModulus) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
-
- string exported;
- ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &exported));
-
- const uint8_t* p = reinterpret_cast<const uint8_t*>(exported.data());
- unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
- unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pkey.get()));
-
- size_t modulus_len = BN_num_bytes(rsa->n);
- ASSERT_EQ(256U / 8, modulus_len);
- unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
- BN_bn2bin(rsa->n, modulus_buf.get());
-
- // The modulus is too big to encrypt.
- string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&result));
-
- // One smaller than the modulus is okay.
- BN_sub(rsa->n, rsa->n, BN_value_one());
- modulus_len = BN_num_bytes(rsa->n);
- ASSERT_EQ(256U / 8, modulus_len);
- BN_bn2bin(rsa->n, modulus_buf.get());
- message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
- size_t key_size = 768;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(key_size, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_256)));
-
- string message = "Hello";
- string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext1.size());
-
- string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext2.size());
-
- // OAEP randomizes padding so every result should be different.
- EXPECT_NE(ciphertext1, ciphertext2);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(EncryptionOperationsTest, RsaOaepSha224Success) {
- size_t key_size = 768;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(key_size, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_224)));
-
- string message = "Hello";
- string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext1.size());
-
- string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext2.size());
-
- // OAEP randomizes padding so every result should be different.
- EXPECT_NE(ciphertext1, ciphertext2);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepRoundTrip) {
- size_t key_size = 768;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(key_size, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_256)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext.size());
-
- string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
- EXPECT_EQ(message, plaintext);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepSha224RoundTrip) {
- size_t key_size = 768;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(key_size, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_224)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext.size());
-
- string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
- EXPECT_EQ(message, plaintext);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(512, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_NONE)));
- string message = "Hello World!";
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepUnauthorizedDigest) {
- if (GetParam()->minimal_digest_set())
- // We don't have two supported digests, so we can't try authorizing one and using another.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(512, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_256)));
- string message = "Hello World!";
- // Works because encryption is a public key operation.
- EncryptMessage(string(message), KM_DIGEST_SHA1, KM_PAD_RSA_OAEP);
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
- if (GetParam()->minimal_digest_set())
- // We don't have two supported digests, so we can't try encrypting with one and decrypting
- // with another.
- return;
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(768, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_256)
- .Digest(KM_DIGEST_SHA_2_384)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
-
- string result;
- size_t input_consumed;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
- EXPECT_EQ(0U, result.size());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(512, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA1)));
- string message = "12345678901234567890123";
- string result;
- size_t input_consumed;
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
- EXPECT_EQ(0U, result.size());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaOaepCorruptedDecrypt) {
- size_t key_size = 768;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(768, 3)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_SHA_2_256)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
- EXPECT_EQ(key_size / 8, ciphertext.size());
-
- // Corrupt the ciphertext
- ciphertext[key_size / 8 / 2]++;
-
- string result;
- size_t input_consumed;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
- EXPECT_EQ(0U, result.size());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
- KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
- string message = "Hello World!";
- string ciphertext1 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(512U / 8, ciphertext1.size());
-
- string ciphertext2 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(512U / 8, ciphertext2.size());
-
- // PKCS1 v1.5 randomizes padding so every result should be different.
- EXPECT_NE(ciphertext1, ciphertext2);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaPkcs1RoundTrip) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
- KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(512U / 8, ciphertext.size());
-
- string plaintext = DecryptMessage(ciphertext, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(message, plaintext);
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-#endif
-#if CHECK_FAIL
-TEST_P(EncryptionOperationsTest, RsaRoundTripAllCombinations) {
- size_t key_size = 2048;
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaEncryptionKey(key_size, 3)
- .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT)
- .Padding(KM_PAD_RSA_OAEP)
- .Digest(KM_DIGEST_NONE)
- .Digest(KM_DIGEST_MD5)
- .Digest(KM_DIGEST_SHA1)
- .Digest(KM_DIGEST_SHA_2_224)
- .Digest(KM_DIGEST_SHA_2_256)
- .Digest(KM_DIGEST_SHA_2_384)
- .Digest(KM_DIGEST_SHA_2_512)));
-
- string message = "Hello World!";
-
- keymaster_padding_t padding_modes[] = {KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
- keymaster_digest_t digests[] = {
- KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
- KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
- };
-
- for (auto padding : padding_modes)
- for (auto digest : digests) {
- if (padding == KM_PAD_RSA_OAEP && digest == KM_DIGEST_NONE)
- // OAEP requires a digest.
- continue;
-
- string ciphertext = EncryptMessage(message, digest, padding);
- EXPECT_EQ(key_size / 8, ciphertext.size());
-
- string plaintext = DecryptMessage(ciphertext, digest, padding);
- EXPECT_EQ(message, plaintext);
- }
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(40, GetParam()->keymaster0_calls());
-}
-#endif
-#if RSA_TEST
-TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
- KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
- string message = "123456789012345678901234567890123456789012345678901234";
- string result;
- size_t input_consumed;
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
- EXPECT_EQ(0U, result.size());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaPkcs1CorruptedDecrypt) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
- KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
- string message = "Hello World!";
- string ciphertext = EncryptMessage(string(message), KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(512U / 8, ciphertext.size());
-
- // Corrupt the ciphertext
- ciphertext[512 / 8 / 2]++;
-
- string result;
- size_t input_consumed;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
- EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
- EXPECT_EQ(0U, result.size());
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(4, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, RsaEncryptWithSigningKey) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaSigningKey(256, 3).Padding(KM_PAD_NONE)));
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(2, GetParam()->keymaster0_calls());
-}
-#endif
-#if EC_TEST
-TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(3, GetParam()->keymaster0_calls());
-}
-#endif
-#if HMAC_TEST
-TEST_P(EncryptionOperationsTest, HmacEncrypt) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .HmacKey(128)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
- ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Padding(KM_PAD_NONE)));
- // Two-block message.
- string message = "12345678901234567890123456789012";
- string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- EXPECT_EQ(message.size(), ciphertext1.size());
-
- string ciphertext2 = EncryptMessage(string(message), KM_MODE_ECB, KM_PAD_NONE);
- EXPECT_EQ(message.size(), ciphertext2.size());
-
- // ECB is deterministic.
- EXPECT_EQ(ciphertext1, ciphertext2);
-
- string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE);
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesEcbNotAuthorized) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Padding(KM_PAD_NONE)));
- // Two-block message.
- string message = "12345678901234567890123456789012";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Padding(KM_PAD_NONE)));
- // Message is slightly shorter than two blocks.
- string message = "1234567890123456789012345678901";
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- string ciphertext;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &ciphertext, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&ciphertext));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
-
- // Try various message lengths; all should work.
- for (size_t i = 0; i < 32; ++i) {
- string message(i, 'a');
- string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
- EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
- string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
- EXPECT_EQ(message, plaintext);
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesEcbNoPaddingKeyWithPkcs7Padding) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Authorization(TAG_PADDING, KM_PAD_NONE)));
-
- // Try various message lengths; all should fail.
- for (size_t i = 0; i < 32; ++i) {
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE,
- BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
-
- string message = "a";
- string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
- EXPECT_EQ(16U, ciphertext.size());
- EXPECT_NE(ciphertext, message);
- ++ciphertext[ciphertext.size() / 2];
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- string plaintext;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
- .Padding(KM_PAD_NONE)));
- string message = "123";
- string iv1;
- string ciphertext1 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv1);
- EXPECT_EQ(message.size(), ciphertext1.size());
- EXPECT_EQ(16U, iv1.size());
-
- string iv2;
- string ciphertext2 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv2);
- EXPECT_EQ(message.size(), ciphertext2.size());
- EXPECT_EQ(16U, iv2.size());
-
- // IVs should be random, so ciphertexts should differ.
- EXPECT_NE(iv1, iv2);
- EXPECT_NE(ciphertext1, ciphertext2);
-
- string plaintext = DecryptMessage(ciphertext1, KM_MODE_CTR, KM_PAD_NONE, iv1);
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
- .Padding(KM_PAD_NONE)));
-
- int increment = 15;
- string message(239, 'a');
- AuthorizationSet input_params(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- AuthorizationSet output_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
-
- string ciphertext;
- size_t input_consumed;
- for (size_t i = 0; i < message.size(); i += increment)
- EXPECT_EQ(KM_ERROR_OK,
- UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
- EXPECT_EQ(message.size(), ciphertext.size());
-
- // Move TAG_NONCE into input_params
- input_params.Reinitialize(output_params);
- input_params.push_back(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- output_params.Clear();
-
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
- string plaintext;
- for (size_t i = 0; i < ciphertext.size(); i += increment)
- EXPECT_EQ(KM_ERROR_OK,
- UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
- EXPECT_EQ(ciphertext.size(), plaintext.size());
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-struct AesCtrSp80038aTestVector {
- const char* key;
- const char* nonce;
- const char* plaintext;
- const char* ciphertext;
-};
-
-// These test vectors are taken from
-// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
-static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
- // AES-128
- {
- "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
- "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
- "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
- "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
- },
- // AES-192
- {
- "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
- "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
- "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
- "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
- },
- // AES-256
- {
- "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
- "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
- "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
- "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
- "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
- },
-};
-
-TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
- for (size_t i = 0; i < 3; i++) {
- const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
- const string key = hex2str(test.key);
- const string nonce = hex2str(test.nonce);
- const string plaintext = hex2str(test.plaintext);
- const string ciphertext = hex2str(test.ciphertext);
- CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCtrInvalidPaddingMode) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
- .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
- .Authorization(TAG_CALLER_NONCE)
- .Padding(KM_PAD_NONE)));
-
- AuthorizationSet input_params(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- input_params.push_back(TAG_NONCE, "123", 3);
- EXPECT_EQ(KM_ERROR_INVALID_NONCE, BeginOperation(KM_PURPOSE_ENCRYPT, input_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Padding(KM_PAD_NONE)));
- // Two-block message.
- string message = "12345678901234567890123456789012";
- string iv1;
- string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
- EXPECT_EQ(message.size(), ciphertext1.size());
-
- string iv2;
- string ciphertext2 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv2);
- EXPECT_EQ(message.size(), ciphertext2.size());
-
- // IVs should be random, so ciphertexts should differ.
- EXPECT_NE(iv1, iv2);
- EXPECT_NE(ciphertext1, ciphertext2);
-
- string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCallerNonce) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Authorization(TAG_CALLER_NONCE)
- .Padding(KM_PAD_NONE)));
- string message = "12345678901234567890123456789012";
- string iv1;
- // Don't specify nonce, should get a random one.
- string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
- EXPECT_EQ(message.size(), ciphertext1.size());
- EXPECT_EQ(16U, iv1.size());
-
- string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
- EXPECT_EQ(message, plaintext);
-
- // Now specify a nonce, should also work.
- AuthorizationSet input_params(client_params());
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- string ciphertext2 =
- ProcessMessage(KM_PURPOSE_ENCRYPT, message, input_params, update_params, &output_params);
-
- // Decrypt with correct nonce.
- plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
- &output_params);
- EXPECT_EQ(message, plaintext);
-
- // Now try with wrong nonce.
- input_params.Reinitialize(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- input_params.push_back(TAG_NONCE, "aaaaaaaaaaaaaaaa", 16);
- plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
- &output_params);
- EXPECT_NE(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Padding(KM_PAD_NONE)));
-
- string message = "12345678901234567890123456789012";
- string iv1;
- // Don't specify nonce, should get a random one.
- string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
- EXPECT_EQ(message.size(), ciphertext1.size());
- EXPECT_EQ(16U, iv1.size());
-
- string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
- EXPECT_EQ(message, plaintext);
-
- // Now specify a nonce, should fail.
- AuthorizationSet input_params(client_params());
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
-
- EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
- BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesCbcIncrementalNoPadding) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Padding(KM_PAD_NONE)));
-
- int increment = 15;
- string message(240, 'a');
- AuthorizationSet input_params(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- AuthorizationSet output_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
-
- string ciphertext;
- size_t input_consumed;
- for (size_t i = 0; i < message.size(); i += increment)
- EXPECT_EQ(KM_ERROR_OK,
- UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
- EXPECT_EQ(message.size(), ciphertext.size());
-
- // Move TAG_NONCE into input_params
- input_params.Reinitialize(output_params);
- input_params.push_back(client_params());
- input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
- input_params.push_back(TAG_PADDING, KM_PAD_NONE);
- output_params.Clear();
-
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
- string plaintext;
- for (size_t i = 0; i < ciphertext.size(); i += increment)
- EXPECT_EQ(KM_ERROR_OK,
- UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
- EXPECT_EQ(ciphertext.size(), plaintext.size());
- EXPECT_EQ(message, plaintext);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesCbcPkcs7Padding) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
- .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
-
- // Try various message lengths; all should work.
- for (size_t i = 0; i < 32; ++i) {
- string message(i, 'a');
- string iv;
- string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv);
- EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
- string plaintext = DecryptMessage(ciphertext, KM_MODE_CBC, KM_PAD_PKCS7, iv);
- EXPECT_EQ(message, plaintext);
- }
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string aad = "foobar";
- string message = "123456789012345678901234567890123456";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- string ciphertext;
- size_t input_consumed;
- AuthorizationSet update_out_params;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Grab nonce
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
- EXPECT_EQ(message, plaintext);
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string aad = "foobar";
- string message = "123456789012345678901234567890123456";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 96);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
-
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
- BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string aad = "foobar";
- string message = "123456789012345678901234567890123456";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- string ciphertext;
- size_t input_consumed;
- AuthorizationSet update_out_params;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Grab nonce
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.Reinitialize(client_params());
- begin_params.push_back(begin_out_params);
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 96);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
- uint8_t nonce[] = {
- 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
- };
- uint8_t ciphertext[] = {
- 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
- 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
- 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
- 0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
- 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
- };
- string ciphertext_str(reinterpret_cast<char*>(ciphertext), sizeof(ciphertext));
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
- begin_params.push_back(TAG_NONCE, nonce, sizeof(nonce));
-
- string plaintext;
- size_t input_consumed;
-
- // Import correct key and decrypt
- uint8_t good_key[] = {
- 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
- 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
- };
- string good_key_str(reinterpret_cast<char*>(good_key), sizeof(good_key));
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_CALLER_NONCE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128),
- KM_KEY_FORMAT_RAW, good_key_str));
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed));
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
- // Import bad key and decrypt
- uint8_t bad_key[] = {
- 0xbb, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
- 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
- };
- string bad_key_str(reinterpret_cast<char*>(bad_key), sizeof(bad_key));
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128),
- KM_KEY_FORMAT_RAW, bad_key_str));
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed));
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string aad = "123456789012345678";
- string empty_message;
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- string ciphertext;
- size_t input_consumed;
- AuthorizationSet update_out_params;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, empty_message, &update_out_params,
- &ciphertext, &input_consumed));
- EXPECT_EQ(0U, input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Grab nonce
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
- EXPECT_EQ(empty_message, plaintext);
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, "b", 1);
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- string ciphertext;
- size_t input_consumed;
- AuthorizationSet update_out_params;
-
- // Send AAD, incrementally
- for (int i = 0; i < 1000; ++i) {
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(0U, input_consumed);
- EXPECT_EQ(0U, ciphertext.size());
- }
-
- // Now send data, incrementally, no data.
- AuthorizationSet empty_params;
- for (int i = 0; i < 1000; ++i) {
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, "a", &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(1U, input_consumed);
- }
- EXPECT_EQ(1000U, ciphertext.size());
-
- // And finish.
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
- EXPECT_EQ(1016U, ciphertext.size());
-
- // Grab nonce
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- string plaintext;
-
- // Send AAD, incrementally, no data
- for (int i = 0; i < 1000; ++i) {
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &plaintext,
- &input_consumed));
- EXPECT_EQ(0U, input_consumed);
- EXPECT_EQ(0U, plaintext.size());
- }
-
- // Now send data, incrementally.
- for (size_t i = 0; i < ciphertext.length(); ++i) {
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, string(ciphertext.data() + i, 1),
- &update_out_params, &plaintext, &input_consumed));
- EXPECT_EQ(1U, input_consumed);
- }
- EXPECT_EQ(1000U, plaintext.size());
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string message = "123456789012345678901234567890123456";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
- AuthorizationSet begin_out_params;
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, "foo", 3);
-
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
-
- // No data, AAD only.
- string ciphertext;
- size_t input_consumed;
- AuthorizationSet update_out_params;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "" /* message */, &update_out_params,
- &ciphertext, &input_consumed));
- EXPECT_EQ(0U, input_consumed);
-
- // AAD and data.
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Grab nonce.
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- // Decrypt
- update_params.Clear();
- update_params.push_back(TAG_ASSOCIATED_DATA, "foofoo", 6);
-
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
- EXPECT_EQ(message, plaintext);
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string message = "12345678901234567890123456789012";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
-
- AuthorizationSet finish_params;
- AuthorizationSet finish_out_params;
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- AuthorizationSet update_out_params;
- string ciphertext;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Grab nonce
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- update_params.Clear();
- update_params.push_back(TAG_ASSOCIATED_DATA, "barfoo" /* Wrong AAD */, 6);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string message = "12345678901234567890123456789012";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
-
- // Encrypt
- AuthorizationSet begin_out_params;
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- AuthorizationSet update_out_params;
- string ciphertext;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- begin_params.push_back(TAG_NONCE, "123456789012", 12);
-
- // Decrypt
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
- // With wrong nonce, should have gotten garbage plaintext.
- EXPECT_NE(message, plaintext);
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if AES_TEST
-TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MIN_MAC_LENGTH, 128)));
- string aad = "foobar";
- string message = "123456789012345678901234567890123456";
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- begin_params.push_back(TAG_MAC_LENGTH, 128);
- AuthorizationSet begin_out_params;
-
- AuthorizationSet update_params;
- update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
-
- // Encrypt
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
- AuthorizationSet update_out_params;
- string ciphertext;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
- &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
-
- // Corrupt tag
- (*ciphertext.rbegin())++;
-
- // Grab nonce.
- EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
- begin_params.push_back(begin_out_params);
-
- // Decrypt.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
- string plaintext;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
- &plaintext, &input_consumed));
- EXPECT_EQ(ciphertext.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
- EXPECT_EQ(message, plaintext);
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test MaxOperationsTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, MaxOperationsTest, test_params);
-#if MAX_TEST
-TEST_P(MaxOperationsTest, TestLimit) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .EcbMode()
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
-
- string message = "1234567890123456";
- string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
-
- // Fourth time should fail.
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(MaxOperationsTest, TestAbort) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .EcbMode()
- .Authorization(TAG_PADDING, KM_PAD_NONE)
- .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
-
- string message = "1234567890123456";
- string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
-
- // Fourth time should fail.
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test AddEntropyTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AddEntropyTest, test_params);
-#if ENTROPY_TEST
-TEST_P(AddEntropyTest, AddEntropy) {
- // There's no obvious way to test that entropy is actually added, but we can test that the API
- // doesn't blow up or return an error.
- EXPECT_EQ(KM_ERROR_OK,
- device()->add_rng_entropy(device(), reinterpret_cast<const uint8_t*>("foo"), 3));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-typedef Keymaster2Test Keymaster0AdapterTest;
-#if 0
-INSTANTIATE_TEST_CASE_P(
- AndroidKeymasterTest, Keymaster0AdapterTest,
- ::testing::Values(
- InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
- InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */))));
-#endif
-TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1RsaBlob) {
- // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted
- // key data.
- string km1_sw = read_file("km1_sw_rsa_512.blob");
- EXPECT_EQ(486U, km1_sw.length());
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
- memcpy(key_data, km1_sw.data(), km1_sw.length());
- set_key_blob(key_data, km1_sw.length());
-
- string message(64, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(Keymaster0AdapterTest, UnversionedSoftwareKeymaster1RsaBlob) {
- // Load and use an old-style Keymaster1 software key blob, without the version byte. These
- // blobs contain OCB-encrypted key data.
- string km1_sw = read_file("km1_sw_rsa_512_unversioned.blob");
- EXPECT_EQ(477U, km1_sw.length());
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
- memcpy(key_data, km1_sw.data(), km1_sw.length());
- set_key_blob(key_data, km1_sw.length());
-
- string message(64, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1EcdsaBlob) {
- // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted
- // key data.
- string km1_sw = read_file("km1_sw_ecdsa_256.blob");
- EXPECT_EQ(270U, km1_sw.length());
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
- memcpy(key_data, km1_sw.data(), km1_sw.length());
- set_key_blob(key_data, km1_sw.length());
-
- string message(32, static_cast<char>(0xFF));
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-struct Malloc_Delete {
- void operator()(void* p) { free(p); }
-};
-
-TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster0RsaBlob) {
- // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
- string km0_sw = read_file("km0_sw_rsa_512.blob");
- EXPECT_EQ(333U, km0_sw.length());
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
- memcpy(key_data, km0_sw.data(), km0_sw.length());
- set_key_blob(key_data, km0_sw.length());
-
- string message(64, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(Keymaster0AdapterTest, OldSwKeymaster0RsaBlobGetCharacteristics) {
- // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
- string km0_sw = read_file("km0_sw_rsa_512.blob");
- EXPECT_EQ(333U, km0_sw.length());
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
- memcpy(key_data, km0_sw.data(), km0_sw.length());
- set_key_blob(key_data, km0_sw.length());
-
- EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
- EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
- EXPECT_TRUE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
- EXPECT_TRUE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
- EXPECT_TRUE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
- EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
- EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
- EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
- EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlob) {
- // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
- string km0_sw = read_file("km0_sw_rsa_512.blob");
- EXPECT_EQ(333U, km0_sw.length());
-
- // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
- // be recognized as a software key. Do the same here to pretend this is a hardware key.
- EXPECT_EQ('P', km0_sw[0]);
- km0_sw[0] = 'Q';
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
- memcpy(key_data, km0_sw.data(), km0_sw.length());
- set_key_blob(key_data, km0_sw.length());
-
- string message(64, 'a');
- string signature;
- SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
- VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
- EXPECT_EQ(5, GetParam()->keymaster0_calls());
-}
-
-TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlobGetCharacteristics) {
- // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
- string km0_sw = read_file("km0_sw_rsa_512.blob");
- EXPECT_EQ(333U, km0_sw.length());
-
- // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
- // be recognized as a software key. Do the same here to pretend this is a hardware key.
- EXPECT_EQ('P', km0_sw[0]);
- km0_sw[0] = 'Q';
-
- uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
- memcpy(key_data, km0_sw.data(), km0_sw.length());
- set_key_blob(key_data, km0_sw.length());
-
- EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
- EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 512));
- EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_MD5));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA1));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_224));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_256));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_384));
- EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_512));
- EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_NONE));
- EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT));
- EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN));
- EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_OAEP));
- EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PSS));
- EXPECT_EQ(15U, hw_enforced().size());
-
- EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
- EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
- EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
- EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
-
- EXPECT_FALSE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
- EXPECT_FALSE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
- EXPECT_FALSE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
- EXPECT_FALSE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
- EXPECT_FALSE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
-
- EXPECT_EQ(1, GetParam()->keymaster0_calls());
-}
-
-typedef Keymaster2Test AttestationTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AttestationTest, test_params);
-
-#if ATTESTATIONTEST
-static X509* parse_cert_blob(const keymaster_blob_t& blob) {
- const uint8_t* p = blob.data;
- return d2i_X509(nullptr, &p, blob.data_length);
-}
-
-static bool verify_chain(const keymaster_cert_chain_t& chain) {
- for (size_t i = 0; i < chain.entry_count - 1; ++i) {
- keymaster_blob_t& key_cert_blob = chain.entries[i];
- keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
-
- X509_Ptr key_cert(parse_cert_blob(key_cert_blob));
- X509_Ptr signing_cert(parse_cert_blob(signing_cert_blob));
- EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
- if (!key_cert.get() || !signing_cert.get())
- return false;
-
- EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
- EXPECT_TRUE(!!signing_pubkey.get());
- if (!signing_pubkey.get())
- return false;
-
- EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
- << "Verification of certificate " << i << " failed";
- }
-
- return true;
-}
-
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-static ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
- ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
- EXPECT_TRUE(!!oid.get());
- if (!oid.get())
- return nullptr;
-
- int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
- EXPECT_NE(-1, location);
- if (location == -1)
- return nullptr;
-
- X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
- EXPECT_TRUE(!!attest_rec_ext);
- if (!attest_rec_ext)
- return nullptr;
-
- ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
- EXPECT_TRUE(!!attest_rec);
- return attest_rec;
-}
-
-static bool verify_attestation_record(const string& challenge,
- AuthorizationSet expected_sw_enforced,
- AuthorizationSet expected_tee_enforced,
- uint32_t expected_keymaster_version,
- keymaster_security_level_t expected_keymaster_security_level,
- const keymaster_blob_t& attestation_cert) {
-
- X509_Ptr cert(parse_cert_blob(attestation_cert));
- EXPECT_TRUE(!!cert.get());
- if (!cert.get())
- return false;
-
- ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
- EXPECT_TRUE(!!attest_rec);
- if (!attest_rec)
- return false;
-
- AuthorizationSet att_sw_enforced;
- AuthorizationSet att_tee_enforced;
- uint32_t att_attestation_version;
- uint32_t att_keymaster_version;
- keymaster_security_level_t att_attestation_security_level;
- keymaster_security_level_t att_keymaster_security_level;
- keymaster_blob_t att_challenge = {};
- keymaster_blob_t att_unique_id = {};
-
- EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(
- attest_rec->data, attest_rec->length, &att_attestation_version,
- &att_attestation_security_level, &att_keymaster_version,
- &att_keymaster_security_level, &att_challenge, &att_sw_enforced,
- &att_tee_enforced, &att_unique_id));
-
- EXPECT_EQ(1U, att_attestation_version);
- EXPECT_EQ(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, att_attestation_security_level);
- EXPECT_EQ(expected_keymaster_version, att_keymaster_version);
- EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level);
-
- EXPECT_EQ(challenge.length(), att_challenge.data_length);
- EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data, challenge.length()));
-
- // Add TAG_USER_ID to the relevant attestation list, because user IDs are not included in
- // attestations, since they're meaningless off-device.
- uint32_t user_id;
- if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id))
- att_sw_enforced.push_back(TAG_USER_ID, user_id);
- if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
- att_tee_enforced.push_back(TAG_USER_ID, user_id);
-
- // Add TAG_INCLUDE_UNIQUE_ID to the relevant attestation list, because that tag is not included
- // in the attestation.
- if (expected_sw_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
- att_sw_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
- if (expected_tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
- att_tee_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
-
- att_sw_enforced.Sort();
- expected_sw_enforced.Sort();
- EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
-
- att_tee_enforced.Sort();
- expected_tee_enforced.Sort();
- EXPECT_EQ(expected_tee_enforced, att_tee_enforced);
-
- return true;
-}
-#endif
-#if ATTESTATIONTEST
-TEST_P(AttestationTest, RsaAttestation) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)
- .Authorization(TAG_INCLUDE_UNIQUE_ID)));
-
- keymaster_cert_chain_t cert_chain;
- EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
- EXPECT_EQ(3U, cert_chain.entry_count);
- EXPECT_TRUE(verify_chain(cert_chain));
-
- uint32_t expected_keymaster_version;
- keymaster_security_level_t expected_keymaster_security_level;
- expected_keymaster_version = 2;
- expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
-
- EXPECT_TRUE(verify_attestation_record(
- "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
- expected_keymaster_security_level, cert_chain.entries[0]));
-
- keymaster_free_cert_chain(&cert_chain);
-}
-#endif
-#if ATTESTATIONTEST
-TEST_P(AttestationTest, EcAttestation) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
- KM_DIGEST_SHA_2_256)));
-
- uint32_t expected_keymaster_version;
- keymaster_security_level_t expected_keymaster_security_level;
- expected_keymaster_version = 2;
- expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
-
- keymaster_cert_chain_t cert_chain;
- EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
- EXPECT_EQ(3U, cert_chain.entry_count);
- EXPECT_TRUE(verify_chain(cert_chain));
- EXPECT_TRUE(verify_attestation_record(
- "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
- expected_keymaster_security_level, cert_chain.entries[0]));
-
- keymaster_free_cert_chain(&cert_chain);
-}
-#endif
-typedef Keymaster2Test KeyUpgradeTest;
-INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, KeyUpgradeTest, test_params);
-#if KEYUPGRADETEST
-TEST_P(KeyUpgradeTest, AesVersionUpgrade) {
- // A workaround for testing TEE based keymaster 2 from normal world
- keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context();
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info);
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .AesEncryptionKey(128)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
- .Padding(KM_PAD_NONE)));
-
- // Key should operate fine.
- string message = "1234567890123456";
- string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
-
- // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
- AuthorizationSet version_info_1_2(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 2));
- device->configure(device, &version_info_1_2);
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- if (GetParam()->is_keymaster1_hw()) {
- // Keymaster1 hardware can't support version binding. The key will work regardless
- // of system version. Just abort the remainder of the test.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, AbortOperation());
- return;
- }
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- // Getting characteristics should also fail
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
-
- // Upgrade key.
- EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
-
- // Key should work again
- ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
- EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
-
- // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
- AuthorizationSet version_info_1_1(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info_1_1);
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
-
- // Upgrade should fail
- EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
- EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-#endif
-#if 0//KEYUPGRADETEST
-//this test is no longer valid because boring ssl rejects rsa keys less than 256 bits
-TEST_P(KeyUpgradeTest, RsaVersionUpgrade) {
- keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context();
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info);
-
- ASSERT_EQ(KM_ERROR_OK,
- GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(128, 3).Padding(KM_PAD_NONE)));
-
- // Key should operate fine.
- string message = "1234567890123456";
- string ciphertext = EncryptMessage(message, KM_PAD_NONE);
- EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
-
- // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
- AuthorizationSet version_info_1_2(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 2));
- device->configure(device, &version_info_1_2);
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- if (GetParam()->is_keymaster1_hw()) {
- // Keymaster1 hardware can't support version binding. The key will work regardless
- // of system version. Just abort the remainder of the test.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_OK, AbortOperation());
- return;
- }
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
- // Getting characteristics should also fail
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
-
- // Upgrade key.
- EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
-
- // Key should work again
- ciphertext = EncryptMessage(message, KM_PAD_NONE);
- EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
-
- // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
- AuthorizationSet version_info_1_1(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info_1_1);
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
-
- // Upgrade should fail
- EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
- EXPECT_EQ(7, GetParam()->keymaster0_calls());
-}
-#endif
-#if KEYUPGRADETEST
-TEST_P(KeyUpgradeTest, EcVersionUpgrade) {
- keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context();
- AuthorizationSet version_info(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info);
-
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
- KM_DIGEST_SHA_2_256)));
-
- // Key should operate fine.
- string message = "1234567890123456";
- string signature;
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
-
- // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
- AuthorizationSet version_info_1_2(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 2));
- device->configure(device, &version_info_1_2);
-
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
- if (GetParam()->is_keymaster1_hw()) {
- // Keymaster1 hardware can't support version binding. The key will work regardless
- // of system version. Just abort the remainder of the test.
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
- EXPECT_EQ(KM_ERROR_OK, AbortOperation());
- return;
- }
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
- // Getting characteristics should also fail
- EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
-
- // Upgrade key.
- EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
-
- // Key should work again
- SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
- VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
-
- // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
- AuthorizationSet version_info_1_1(AuthorizationSetBuilder()
- .Authorization(TAG_OS_VERSION, 1)
- .Authorization(TAG_OS_PATCHLEVEL, 1));
- device->configure(device, &version_info_1_1);
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
-
- // Upgrade should fail
- EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(7, GetParam()->keymaster0_calls());
-}
-#endif
-#if 0
-TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
- // Make a good fake device, and wrap it.
- SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
-
- // Wrap it and check it.
- SoftKeymasterDevice* good_fake_wrapper(new SoftKeymasterDevice(new TestKeymasterContext));
- good_fake_wrapper->SetHardwareDevice(good_fake->keymaster_device());
- EXPECT_TRUE(good_fake_wrapper->Keymaster1DeviceIsGood());
-
- // Close and clean up wrapper and wrapped
- good_fake_wrapper->keymaster_device()->common.close(good_fake_wrapper->hw_device());
-
- // Make a "bad" (doesn't support all digests) device;
- keymaster1_device_t* sha256_only_fake = make_device_sha256_only(
- (new SoftKeymasterDevice(new TestKeymasterContext("256")))->keymaster_device());
-
- // Wrap it and check it.
- SoftKeymasterDevice* sha256_only_fake_wrapper(
- (new SoftKeymasterDevice(new TestKeymasterContext)));
- sha256_only_fake_wrapper->SetHardwareDevice(sha256_only_fake);
- EXPECT_FALSE(sha256_only_fake_wrapper->Keymaster1DeviceIsGood());
-
- // Close and clean up wrapper and wrapped
- sha256_only_fake_wrapper->keymaster_device()->common.close(
- sha256_only_fake_wrapper->hw_device());
-}
-#endif
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/android_keymaster_test_utils.cpp b/unit_test/android_keymaster_test_utils.cpp
deleted file mode 100644
index ecaee62..0000000
--- a/unit_test/android_keymaster_test_utils.cpp
+++ b/dev/null
@@ -1,902 +0,0 @@
-/*
- * Copyright 2014 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_keymaster_test_utils.h"
-
-#include <algorithm>
-
-#include <openssl/rand.h>
-
-#include <keymaster/android_keymaster_messages.h>
-#include <keymaster/android_keymaster_utils.h>
-
-using std::copy_if;
-using std::find_if;
-using std::is_permutation;
-using std::ostream;
-using std::string;
-using std::vector;
-
-#ifndef KEYMASTER_NAME_TAGS
-#error Keymaster test code requires that KEYMASTER_NAME_TAGS is defined
-#endif
-
-std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param) {
- os << "Tag: " << keymaster::StringifyTag(param.tag);
- switch (keymaster_tag_get_type(param.tag)) {
- case KM_INVALID:
- os << " Invalid";
- break;
- case KM_UINT_REP:
- os << " (Rep)";
- /* Falls through */
- case KM_UINT:
- os << " Int: " << param.integer;
- break;
- case KM_ENUM_REP:
- os << " (Rep)";
- /* Falls through */
- case KM_ENUM:
- os << " Enum: " << param.enumerated;
- break;
- case KM_ULONG_REP:
- os << " (Rep)";
- /* Falls through */
- case KM_ULONG:
- os << " Long: " << param.long_integer;
- break;
- case KM_DATE:
- os << " Date: " << param.date_time;
- break;
- case KM_BOOL:
- os << " Bool: " << param.boolean;
- break;
- case KM_BIGNUM:
- os << " Bignum: ";
- if (!param.blob.data)
- os << "(null)";
- else
- for (size_t i = 0; i < param.blob.data_length; ++i)
- os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
- break;
- case KM_BYTES:
- os << " Bytes: ";
- if (!param.blob.data)
- os << "(null)";
- else
- for (size_t i = 0; i < param.blob.data_length; ++i)
- os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
- break;
- }
- return os;
-}
-
-bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b) {
- if (a.tag != b.tag) {
- return false;
- }
-
- switch (keymaster_tag_get_type(a.tag)) {
- case KM_INVALID:
- return true;
- case KM_UINT_REP:
- case KM_UINT:
- return a.integer == b.integer;
- case KM_ENUM_REP:
- case KM_ENUM:
- return a.enumerated == b.enumerated;
- case KM_ULONG:
- case KM_ULONG_REP:
- return a.long_integer == b.long_integer;
- case KM_DATE:
- return a.date_time == b.date_time;
- case KM_BOOL:
- return a.boolean == b.boolean;
- case KM_BIGNUM:
- case KM_BYTES:
- if ((a.blob.data == NULL || b.blob.data == NULL) && a.blob.data != b.blob.data)
- return false;
- return a.blob.data_length == b.blob.data_length &&
- (memcmp(a.blob.data, b.blob.data, a.blob.data_length) == 0);
- }
-
- return false;
-}
-
-static char hex_value[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
- 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-string hex2str(string a) {
- string b;
- size_t num = a.size() / 2;
- b.resize(num);
- for (size_t i = 0; i < num; i++) {
- b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
- }
- return b;
-}
-
-namespace keymaster {
-
-bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
- if (a.size() != b.size())
- return false;
-
- for (size_t i = 0; i < a.size(); ++i)
- if (!(a[i] == b[i]))
- return false;
- return true;
-}
-
-bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b) {
- return !(a == b);
-}
-
-std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set) {
- if (set.size() == 0)
- os << "(Empty)" << std::endl;
- else {
- os << "\n";
- for (size_t i = 0; i < set.size(); ++i)
- os << set[i] << std::endl;
- }
- return os;
-}
-
-namespace test {
-
-Keymaster2Test::Keymaster2Test() : op_handle_(OP_HANDLE_SENTINEL) {
- memset(&characteristics_, 0, sizeof(characteristics_));
- blob_.key_material = nullptr;
- RAND_seed("foobar", 6);
- blob_.key_material = 0;
- device_ = GetParam()->CreateDevice();
-}
-
-Keymaster2Test::~Keymaster2Test() {
- FreeCharacteristics();
- FreeKeyBlob();
- device_->common.close(reinterpret_cast<hw_device_t*>(device_));
-}
-
-keymaster2_device_t* Keymaster2Test::device() {
- return device_;
-}
-
-keymaster_error_t Keymaster2Test::GenerateKey(const AuthorizationSetBuilder& builder) {
- AuthorizationSet params(builder.build());
- params.push_back(UserAuthParams());
- params.push_back(ClientParams());
-
- FreeKeyBlob();
- FreeCharacteristics();
- return device()->generate_key(device(), &params, &blob_, &characteristics_);
-}
-
-keymaster_error_t Keymaster2Test::DeleteKey() {
- return device()->delete_key(device(), &blob_);
-}
-
-keymaster_error_t Keymaster2Test::ImportKey(const AuthorizationSetBuilder& builder,
- keymaster_key_format_t format,
- const string& key_material) {
- AuthorizationSet params(builder.build());
- params.push_back(UserAuthParams());
- params.push_back(ClientParams());
-
- FreeKeyBlob();
- FreeCharacteristics();
- keymaster_blob_t key = {reinterpret_cast<const uint8_t*>(key_material.c_str()),
- key_material.length()};
- return device()->import_key(device(), &params, format, &key, &blob_, &characteristics_);
-}
-
-AuthorizationSet Keymaster2Test::UserAuthParams() {
- AuthorizationSet set;
- set.push_back(TAG_USER_ID, 7);
- set.push_back(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD);
- set.push_back(TAG_AUTH_TIMEOUT, 300);
- return set;
-}
-
-AuthorizationSet Keymaster2Test::ClientParams() {
- AuthorizationSet set;
- set.push_back(TAG_APPLICATION_ID, "app_id", 6);
- return set;
-}
-
-keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose) {
- AuthorizationSet in_params(client_params());
- keymaster_key_param_set_t out_params;
- keymaster_error_t error =
- device()->begin(device(), purpose, &blob_, &in_params, &out_params, &op_handle_);
- EXPECT_EQ(0U, out_params.length);
- EXPECT_TRUE(out_params.params == nullptr);
- return error;
-}
-
-keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose,
- const AuthorizationSet& input_set,
- AuthorizationSet* output_set) {
- keymaster_key_param_set_t out_params;
- keymaster_error_t error =
- device()->begin(device(), purpose, &blob_, &input_set, &out_params, &op_handle_);
- if (error == KM_ERROR_OK) {
- if (output_set) {
- output_set->Reinitialize(out_params);
- } else {
- EXPECT_EQ(0U, out_params.length);
- EXPECT_TRUE(out_params.params == nullptr);
- }
- keymaster_free_param_set(&out_params);
- }
- return error;
-}
-
-keymaster_error_t Keymaster2Test::UpdateOperation(const string& message, string* output,
- size_t* input_consumed) {
- EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
- keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
- keymaster_blob_t out_tmp;
- keymaster_key_param_set_t out_params;
- keymaster_error_t error = device()->update(device(), op_handle_, nullptr /* params */, &input,
- input_consumed, &out_params, &out_tmp);
- if (error == KM_ERROR_OK && out_tmp.data)
- output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
- free(const_cast<uint8_t*>(out_tmp.data));
- return error;
-}
-
-keymaster_error_t Keymaster2Test::UpdateOperation(const AuthorizationSet& additional_params,
- const string& message,
- AuthorizationSet* output_params, string* output,
- size_t* input_consumed) {
- EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
- keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
- keymaster_blob_t out_tmp;
- keymaster_key_param_set_t out_params;
- keymaster_error_t error = device()->update(device(), op_handle_, &additional_params, &input,
- input_consumed, &out_params, &out_tmp);
- if (error == KM_ERROR_OK && out_tmp.data)
- output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
- free((void*)out_tmp.data);
- if (output_params)
- output_params->Reinitialize(out_params);
- keymaster_free_param_set(&out_params);
- return error;
-}
-
-keymaster_error_t Keymaster2Test::FinishOperation(string* output) {
- return FinishOperation("", output);
-}
-
-keymaster_error_t Keymaster2Test::FinishOperation(const string& signature, string* output) {
- AuthorizationSet additional_params;
- AuthorizationSet output_params;
- return FinishOperation(additional_params, signature, &output_params, output);
-}
-
-keymaster_error_t Keymaster2Test::FinishOperation(const AuthorizationSet& additional_params,
- const string& signature,
- AuthorizationSet* output_params, string* output) {
- keymaster_blob_t sig = {reinterpret_cast<const uint8_t*>(signature.c_str()),
- signature.length()};
- keymaster_blob_t out_tmp;
- keymaster_key_param_set_t out_params;
- keymaster_error_t error = device()->finish(device(), op_handle_, &additional_params,
- nullptr /* input */, &sig, &out_params, &out_tmp);
- if (error != KM_ERROR_OK) {
- EXPECT_TRUE(out_tmp.data == nullptr);
- EXPECT_TRUE(out_params.params == nullptr);
- return error;
- }
-
- if (out_tmp.data)
- output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
- free((void*)out_tmp.data);
- if (output_params)
- output_params->Reinitialize(out_params);
- keymaster_free_param_set(&out_params);
- return error;
-}
-
-keymaster_error_t Keymaster2Test::AbortOperation() {
- return device()->abort(device(), op_handle_);
-}
-
-keymaster_error_t Keymaster2Test::AttestKey(const string& attest_challenge,
- keymaster_cert_chain_t* cert_chain) {
- AuthorizationSet attest_params;
- attest_params.push_back(UserAuthParams());
- attest_params.push_back(ClientParams());
- attest_params.push_back(TAG_ATTESTATION_CHALLENGE, attest_challenge.data(),
- attest_challenge.length());
- return device()->attest_key(device(), &blob_, &attest_params, cert_chain);
-}
-
-keymaster_error_t Keymaster2Test::UpgradeKey(const AuthorizationSet& upgrade_params) {
- keymaster_key_blob_t upgraded_blob;
- keymaster_error_t error =
- device()->upgrade_key(device(), &blob_, &upgrade_params, &upgraded_blob);
- if (error == KM_ERROR_OK) {
- FreeKeyBlob();
- blob_ = upgraded_blob;
- }
- return error;
-}
-
-string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
- return result;
-}
-
-string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
- const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* begin_out_params) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, begin_out_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
- &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, "", &result));
- return result;
-}
-
-string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
- const string& signature, const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* output_params) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, output_params));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
- &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, signature, &result));
- return result;
-}
-
-string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
- const string& signature) {
- EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
-
- string result;
- size_t input_consumed;
- EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
- EXPECT_EQ(message.size(), input_consumed);
- EXPECT_EQ(KM_ERROR_OK, FinishOperation(signature, &result));
- return result;
-}
-
-void Keymaster2Test::SignMessage(const string& message, string* signature,
- keymaster_digest_t digest) {
- SCOPED_TRACE("SignMessage");
- AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
- input_params.push_back(TAG_DIGEST, digest);
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- *signature =
- ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
- EXPECT_GT(signature->size(), 0U);
-}
-
-void Keymaster2Test::SignMessage(const string& message, string* signature,
- keymaster_digest_t digest, keymaster_padding_t padding) {
- SCOPED_TRACE("SignMessage");
- AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
- input_params.push_back(TAG_DIGEST, digest);
- input_params.push_back(TAG_PADDING, padding);
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- *signature =
- ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
- EXPECT_GT(signature->size(), 0U);
-}
-
-void Keymaster2Test::MacMessage(const string& message, string* signature, size_t mac_length) {
- SCOPED_TRACE("SignMessage");
- AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
- input_params.push_back(TAG_MAC_LENGTH, mac_length);
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- *signature =
- ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
- EXPECT_GT(signature->size(), 0U);
-}
-
-void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
- keymaster_digest_t digest) {
- SCOPED_TRACE("VerifyMessage");
- AuthorizationSet input_params(client_params());
- input_params.push_back(TAG_DIGEST, digest);
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
- &output_params);
-}
-
-void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
- keymaster_digest_t digest, keymaster_padding_t padding) {
- SCOPED_TRACE("VerifyMessage");
- AuthorizationSet input_params(client_params());
- input_params.push_back(TAG_DIGEST, digest);
- input_params.push_back(TAG_PADDING, padding);
- AuthorizationSet update_params;
- AuthorizationSet output_params;
- ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
- &output_params);
-}
-
-void Keymaster2Test::VerifyMac(const string& message, const string& signature) {
- SCOPED_TRACE("VerifyMac");
- ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
-}
-
-string Keymaster2Test::EncryptMessage(const string& message, keymaster_padding_t padding,
- string* generated_nonce) {
- SCOPED_TRACE("EncryptMessage");
- AuthorizationSet begin_params(client_params()), output_params;
- begin_params.push_back(TAG_PADDING, padding);
- AuthorizationSet update_params;
- string ciphertext =
- ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
- if (generated_nonce) {
- keymaster_blob_t nonce_blob;
- EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
- *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
- } else {
- EXPECT_EQ(-1, output_params.find(TAG_NONCE));
- }
- return ciphertext;
-}
-
-string Keymaster2Test::EncryptMessage(const string& message, keymaster_digest_t digest,
- keymaster_padding_t padding, string* generated_nonce) {
- AuthorizationSet update_params;
- return EncryptMessage(update_params, message, digest, padding, generated_nonce);
-}
-
-string Keymaster2Test::EncryptMessage(const string& message, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding, string* generated_nonce) {
- AuthorizationSet update_params;
- return EncryptMessage(update_params, message, block_mode, padding, generated_nonce);
-}
-
-string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
- keymaster_digest_t digest, keymaster_padding_t padding,
- string* generated_nonce) {
- SCOPED_TRACE("EncryptMessage");
- AuthorizationSet begin_params(client_params()), output_params;
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_DIGEST, digest);
- string ciphertext =
- ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
- if (generated_nonce) {
- keymaster_blob_t nonce_blob;
- EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
- *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
- } else {
- EXPECT_EQ(-1, output_params.find(TAG_NONCE));
- }
- return ciphertext;
-}
-
-string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
- keymaster_block_mode_t block_mode,
- keymaster_padding_t padding, string* generated_nonce) {
- SCOPED_TRACE("EncryptMessage");
- AuthorizationSet begin_params(client_params()), output_params;
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_BLOCK_MODE, block_mode);
- string ciphertext =
- ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
- if (generated_nonce) {
- keymaster_blob_t nonce_blob;
- EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
- *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
- } else {
- EXPECT_EQ(-1, output_params.find(TAG_NONCE));
- }
- return ciphertext;
-}
-
-string Keymaster2Test::EncryptMessageWithParams(const string& message,
- const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* output_params) {
- SCOPED_TRACE("EncryptMessageWithParams");
- return ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, output_params);
-}
-
-string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_padding_t padding) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- AuthorizationSet update_params;
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
- keymaster_padding_t padding) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_DIGEST, digest);
- AuthorizationSet update_params;
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_BLOCK_MODE, block_mode);
- AuthorizationSet update_params;
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
- keymaster_padding_t padding, const string& nonce) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_DIGEST, digest);
- begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
- AuthorizationSet update_params;
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding, const string& nonce) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_BLOCK_MODE, block_mode);
- begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
- AuthorizationSet update_params;
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-string Keymaster2Test::DecryptMessage(const AuthorizationSet& update_params,
- const string& ciphertext, keymaster_digest_t digest,
- keymaster_padding_t padding, const string& nonce) {
- SCOPED_TRACE("DecryptMessage");
- AuthorizationSet begin_params(client_params());
- begin_params.push_back(TAG_PADDING, padding);
- begin_params.push_back(TAG_DIGEST, digest);
- begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
- return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
-}
-
-keymaster_error_t Keymaster2Test::GetCharacteristics() {
- FreeCharacteristics();
- return device()->get_key_characteristics(device(), &blob_, &client_id_, NULL /* app_data */,
- &characteristics_);
-}
-
-keymaster_error_t Keymaster2Test::ExportKey(keymaster_key_format_t format, string* export_data) {
- keymaster_blob_t export_tmp;
- keymaster_error_t error = device()->export_key(device(), format, &blob_, &client_id_,
- NULL /* app_data */, &export_tmp);
-
- if (error != KM_ERROR_OK)
- return error;
-
- *export_data = string(reinterpret_cast<const char*>(export_tmp.data), export_tmp.data_length);
- free((void*)export_tmp.data);
- return error;
-}
-
-void Keymaster2Test::CheckHmacTestVector(const string& key, const string& message, keymaster_digest_t digest,
- string expected_mac) {
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .HmacKey(key.size() * 8)
- .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
- .Digest(digest),
- KM_KEY_FORMAT_RAW, key));
- string signature;
- MacMessage(message, &signature, expected_mac.size() * 8);
- EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest;
-}
-
-void Keymaster2Test::CheckAesCtrTestVector(const string& key, const string& nonce,
- const string& message,
- const string& expected_ciphertext) {
- ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
- .AesEncryptionKey(key.size() * 8)
- .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
- .Authorization(TAG_CALLER_NONCE)
- .Padding(KM_PAD_NONE),
- KM_KEY_FORMAT_RAW, key));
-
- AuthorizationSet begin_params(client_params()), update_params, output_params;
- begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
- begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
- begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
- string ciphertext =
- EncryptMessageWithParams(message, begin_params, update_params, &output_params);
- EXPECT_EQ(expected_ciphertext, ciphertext);
-}
-
-AuthorizationSet Keymaster2Test::hw_enforced() {
- return AuthorizationSet(characteristics_.hw_enforced);
-}
-
-AuthorizationSet Keymaster2Test::sw_enforced() {
- return AuthorizationSet(characteristics_.sw_enforced);
-}
-
-void Keymaster2Test::FreeCharacteristics() {
- keymaster_free_characteristics(&characteristics_);
-}
-
-void Keymaster2Test::FreeKeyBlob() {
- free(const_cast<uint8_t*>(blob_.key_material));
- blob_.key_material = NULL;
-}
-
-void Keymaster2Test::corrupt_key_blob() {
- assert(blob_.key_material);
- uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
- ++tmp[blob_.key_material_size / 2];
-}
-
-class Sha256OnlyWrapper {
- public:
- explicit Sha256OnlyWrapper(const keymaster1_device_t* wrapped_device) : wrapped_device_(wrapped_device) {
-
- new_module = *wrapped_device_->common.module;
- new_module_name = std::string("SHA 256-only ") + wrapped_device_->common.module->name;
- new_module.name = new_module_name.c_str();
-
- memset(&device_, 0, sizeof(device_));
- device_.common.module = &new_module;
-
- device_.common.close = close_device;
- device_.get_supported_algorithms = get_supported_algorithms;
- device_.get_supported_block_modes = get_supported_block_modes;
- device_.get_supported_padding_modes = get_supported_padding_modes;
- device_.get_supported_digests = get_supported_digests;
- device_.get_supported_import_formats = get_supported_import_formats;
- device_.get_supported_export_formats = get_supported_export_formats;
- device_.add_rng_entropy = add_rng_entropy;
- device_.generate_key = generate_key;
- device_.get_key_characteristics = get_key_characteristics;
- device_.import_key = import_key;
- device_.export_key = export_key;
- device_.begin = begin;
- device_.update = update;
- device_.finish = finish;
- device_.abort = abort;
- }
-
- keymaster1_device_t* keymaster_device() { return &device_; }
-
- static bool is_supported(keymaster_digest_t digest) {
- return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
- }
-
- static bool all_digests_supported(const keymaster_key_param_set_t* params) {
- for (size_t i = 0; i < params->length; ++i)
- if (params->params[i].tag == TAG_DIGEST)
- if (!is_supported(static_cast<keymaster_digest_t>(params->params[i].enumerated)))
- return false;
- return true;
- }
-
- static const keymaster_key_param_t*
- get_algorithm_param(const keymaster_key_param_set_t* params) {
- keymaster_key_param_t* end = params->params + params->length;
- auto alg_ptr = std::find_if(params->params, end, [](keymaster_key_param_t& p) {
- return p.tag == KM_TAG_ALGORITHM;
- });
- if (alg_ptr == end)
- return nullptr;
- return alg_ptr;
- }
-
- static int close_device(hw_device_t* dev) {
- Sha256OnlyWrapper* wrapper = reinterpret_cast<Sha256OnlyWrapper*>(dev);
- const keymaster1_device_t* wrapped_device = wrapper->wrapped_device_;
- delete wrapper;
- return wrapped_device->common.close(const_cast<hw_device_t*>(&wrapped_device->common));
- }
-
- static const keymaster1_device_t* unwrap(const keymaster1_device_t* dev) {
- return reinterpret_cast<const Sha256OnlyWrapper*>(dev)->wrapped_device_;
- }
-
- static keymaster_error_t get_supported_algorithms(const struct keymaster1_device* dev,
- keymaster_algorithm_t** algorithms,
- size_t* algorithms_length) {
- return unwrap(dev)->get_supported_algorithms(unwrap(dev), algorithms, algorithms_length);
- }
- static keymaster_error_t get_supported_block_modes(const struct keymaster1_device* dev,
- keymaster_algorithm_t algorithm,
- keymaster_purpose_t purpose,
- keymaster_block_mode_t** modes,
- size_t* modes_length) {
- return unwrap(dev)->get_supported_block_modes(unwrap(dev), algorithm, purpose, modes,
- modes_length);
- }
- static keymaster_error_t get_supported_padding_modes(const struct keymaster1_device* dev,
- keymaster_algorithm_t algorithm,
- keymaster_purpose_t purpose,
- keymaster_padding_t** modes,
- size_t* modes_length) {
- return unwrap(dev)->get_supported_padding_modes(unwrap(dev), algorithm, purpose, modes,
- modes_length);
- }
-
- static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev,
- keymaster_algorithm_t algorithm,
- keymaster_purpose_t purpose,
- keymaster_digest_t** digests,
- size_t* digests_length) {
- keymaster_error_t error = unwrap(dev)->get_supported_digests(
- unwrap(dev), algorithm, purpose, digests, digests_length);
- if (error != KM_ERROR_OK)
- return error;
-
- std::vector<keymaster_digest_t> filtered_digests;
- std::copy_if(*digests, *digests + *digests_length, std::back_inserter(filtered_digests),
- [](keymaster_digest_t digest) { return is_supported(digest); });
-
- free(*digests);
- *digests_length = filtered_digests.size();
- *digests = reinterpret_cast<keymaster_digest_t*>(
- malloc(*digests_length * sizeof(keymaster_digest_t)));
- std::copy(filtered_digests.begin(), filtered_digests.end(), *digests);
-
- return KM_ERROR_OK;
- }
-
- static keymaster_error_t get_supported_import_formats(const struct keymaster1_device* dev,
- keymaster_algorithm_t algorithm,
- keymaster_key_format_t** formats,
- size_t* formats_length) {
- return unwrap(dev)->get_supported_import_formats(unwrap(dev), algorithm, formats,
- formats_length);
- }
- static keymaster_error_t get_supported_export_formats(const struct keymaster1_device* dev,
- keymaster_algorithm_t algorithm,
- keymaster_key_format_t** formats,
- size_t* formats_length) {
- return unwrap(dev)->get_supported_export_formats(unwrap(dev), algorithm, formats,
- formats_length);
- }
- static keymaster_error_t add_rng_entropy(const struct keymaster1_device* dev,
- const uint8_t* data, size_t data_length) {
- return unwrap(dev)->add_rng_entropy(unwrap(dev), data, data_length);
- }
-
- static keymaster_error_t generate_key(const keymaster1_device_t* dev,
- const keymaster_key_param_set_t* params,
- keymaster_key_blob_t* key_blob,
- keymaster_key_characteristics_t** characteristics) {
- auto alg_ptr = get_algorithm_param(params);
- if (!alg_ptr)
- return KM_ERROR_UNSUPPORTED_ALGORITHM;
- if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
- return KM_ERROR_UNSUPPORTED_DIGEST;
-
- return unwrap(dev)->generate_key(unwrap(dev), params, key_blob, characteristics);
- }
-
- static keymaster_error_t
- get_key_characteristics(const struct keymaster1_device* dev,
- const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_key_characteristics_t** characteristics) {
- return unwrap(dev)->get_key_characteristics(unwrap(dev), key_blob, client_id, app_data,
- characteristics);
- }
-
- static keymaster_error_t
- import_key(const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
- keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
- keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
- auto alg_ptr = get_algorithm_param(params);
- if (!alg_ptr)
- return KM_ERROR_UNSUPPORTED_ALGORITHM;
- if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
- return KM_ERROR_UNSUPPORTED_DIGEST;
-
- return unwrap(dev)->import_key(unwrap(dev), params, key_format, key_data, key_blob,
- characteristics);
- }
-
- static keymaster_error_t export_key(const struct keymaster1_device* dev, //
- keymaster_key_format_t export_format,
- const keymaster_key_blob_t* key_to_export,
- const keymaster_blob_t* client_id,
- const keymaster_blob_t* app_data,
- keymaster_blob_t* export_data) {
- return unwrap(dev)->export_key(unwrap(dev), export_format, key_to_export, client_id,
- app_data, export_data);
- }
-
- static keymaster_error_t begin(const keymaster1_device_t* dev, //
- keymaster_purpose_t purpose, const keymaster_key_blob_t* key,
- const keymaster_key_param_set_t* in_params,
- keymaster_key_param_set_t* out_params,
- keymaster_operation_handle_t* operation_handle) {
- if (!all_digests_supported(in_params))
- return KM_ERROR_UNSUPPORTED_DIGEST;
- return unwrap(dev)->begin(unwrap(dev), purpose, key, in_params, out_params,
- operation_handle);
- }
-
- static keymaster_error_t update(const keymaster1_device_t* dev,
- keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* input, size_t* input_consumed,
- keymaster_key_param_set_t* out_params,
- keymaster_blob_t* output) {
- return unwrap(dev)->update(unwrap(dev), operation_handle, in_params, input, input_consumed,
- out_params, output);
- }
-
- static keymaster_error_t finish(const struct keymaster1_device* dev, //
- keymaster_operation_handle_t operation_handle,
- const keymaster_key_param_set_t* in_params,
- const keymaster_blob_t* signature,
- keymaster_key_param_set_t* out_params,
- keymaster_blob_t* output) {
- return unwrap(dev)->finish(unwrap(dev), operation_handle, in_params, signature, out_params,
- output);
- }
-
- static keymaster_error_t abort(const struct keymaster1_device* dev,
- keymaster_operation_handle_t operation_handle) {
- return unwrap(dev)->abort(unwrap(dev), operation_handle);
- }
-
- private:
- keymaster1_device_t device_;
- const keymaster1_device_t* wrapped_device_;
- hw_module_t new_module;
- string new_module_name;
-};
-
-keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device) {
- return (new Sha256OnlyWrapper(device))->keymaster_device();
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/android_keymaster_test_utils.h b/unit_test/android_keymaster_test_utils.h
deleted file mode 100644
index 5dd0f76..0000000
--- a/unit_test/android_keymaster_test_utils.h
+++ b/dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright 2014 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 SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
-
-/*
- * Utilities used to help with testing. Not used in production code.
- */
-
-#include <stdarg.h>
-
-#include <algorithm>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <hardware/keymaster0.h>
-#include <hardware/keymaster1.h>
-#include <hardware/keymaster2.h>
-#include <hardware/keymaster_defs.h>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/keymaster_context.h>
-#include <keymaster/logger.h>
-
-std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
-bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b);
-std::string hex2str(std::string);
-
-namespace keymaster {
-
-bool operator==(const AuthorizationSet& a, const AuthorizationSet& b);
-bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b);
-
-std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set);
-
-namespace test {
-
-template <keymaster_tag_t Tag, typename KeymasterEnum>
-bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
- KeymasterEnum val) {
- int pos = set.find(tag);
- return pos != -1 && static_cast<KeymasterEnum>(set[pos].enumerated) == val;
-}
-
-template <keymaster_tag_t Tag, typename KeymasterEnum>
-bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
- KeymasterEnum val) {
- int pos = -1;
- while ((pos = set.find(tag, pos)) != -1)
- if (static_cast<KeymasterEnum>(set[pos].enumerated) == val)
- return true;
- return false;
-}
-
-template <keymaster_tag_t Tag>
-bool contains(const AuthorizationSet& set, TypedTag<KM_UINT, Tag> tag, uint32_t val) {
- int pos = set.find(tag);
- return pos != -1 && set[pos].integer == val;
-}
-
-template <keymaster_tag_t Tag>
-bool contains(const AuthorizationSet& set, TypedTag<KM_UINT_REP, Tag> tag, uint32_t val) {
- int pos = -1;
- while ((pos = set.find(tag, pos)) != -1)
- if (set[pos].integer == val)
- return true;
- return false;
-}
-
-template <keymaster_tag_t Tag>
-bool contains(const AuthorizationSet& set, TypedTag<KM_ULONG, Tag> tag, uint64_t val) {
- int pos = set.find(tag);
- return pos != -1 && set[pos].long_integer == val;
-}
-
-template <keymaster_tag_t Tag>
-bool contains(const AuthorizationSet& set, TypedTag<KM_BYTES, Tag> tag, const std::string& val) {
- int pos = set.find(tag);
- return pos != -1 &&
- std::string(reinterpret_cast<const char*>(set[pos].blob.data),
- set[pos].blob.data_length) == val;
-}
-
-template <keymaster_tag_t Tag>
-bool contains(const AuthorizationSet& set, TypedTag<KM_BIGNUM, Tag> tag, const std::string& val) {
- int pos = set.find(tag);
- return pos != -1 &&
- std::string(reinterpret_cast<const char*>(set[pos].blob.data),
- set[pos].blob.data_length) == val;
-}
-
-inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) {
- return set.find(tag) != -1;
-}
-
-class StdoutLogger : public 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;
- }
-};
-
-inline std::string make_string(const uint8_t* data, size_t length) {
- return std::string(reinterpret_cast<const char*>(data), length);
-}
-
-template <size_t N> std::string make_string(const uint8_t (&a)[N]) {
- return make_string(a, N);
-}
-
-/**
- * Keymaster2TestInstance is used to parameterize Keymaster2Tests. Its main function is to create a
- * keymaster2_device_t to which test calls can be directed. It also provides a place to specify
- * various bits of alternative behavior, in cases where different devices are expected to behave
- * differently (any such cases are a potential bug, but sometimes they may make sense).
- */
-class Keymaster2TestInstanceCreator {
- public:
- virtual ~Keymaster2TestInstanceCreator(){};
- virtual keymaster2_device_t* CreateDevice() const = 0;
-
- virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0;
- virtual int keymaster0_calls() const = 0;
- virtual int minimal_digest_set() const { return false; }
- virtual bool is_keymaster1_hw() const = 0;
- virtual KeymasterContext* keymaster_context() const = 0;
-};
-
-// Use a shared_ptr because it's copyable.
-typedef std::shared_ptr<Keymaster2TestInstanceCreator> InstanceCreatorPtr;
-
-const uint64_t OP_HANDLE_SENTINEL = 0xFFFFFFFFFFFFFFFF;
-class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> {
- protected:
- Keymaster2Test();
- ~Keymaster2Test();
-
- keymaster2_device_t* device();
-
- keymaster_error_t GenerateKey(const AuthorizationSetBuilder& builder);
-
- keymaster_error_t DeleteKey();
-
- keymaster_error_t ImportKey(const AuthorizationSetBuilder& builder,
- keymaster_key_format_t format, const std::string& key_material);
-
- keymaster_error_t ExportKey(keymaster_key_format_t format, std::string* export_data);
-
- keymaster_error_t GetCharacteristics();
-
- keymaster_error_t BeginOperation(keymaster_purpose_t purpose);
- keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set,
- AuthorizationSet* output_set = NULL);
-
- keymaster_error_t UpdateOperation(const std::string& message, std::string* output,
- size_t* input_consumed);
- keymaster_error_t UpdateOperation(const AuthorizationSet& additional_params,
- const std::string& message, AuthorizationSet* output_params,
- std::string* output, size_t* input_consumed);
-
- keymaster_error_t FinishOperation(std::string* output);
- keymaster_error_t FinishOperation(const std::string& signature, std::string* output);
- keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
- const std::string& signature, std::string* output) {
- return FinishOperation(additional_params, signature, nullptr /* output_params */, output);
- }
- keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
- const std::string& signature, AuthorizationSet* output_params,
- std::string* output);
-
- keymaster_error_t AbortOperation();
-
- keymaster_error_t AttestKey(const std::string& attest_challenge, keymaster_cert_chain_t* chain);
-
- keymaster_error_t UpgradeKey(const AuthorizationSet& upgrade_params);
-
- keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor);
-
- std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message);
- std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
- const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* output_params = NULL);
- std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
- const std::string& signature, const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* output_params = NULL);
- std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
- const std::string& signature);
-
- void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest);
- void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest,
- keymaster_padding_t padding);
- void MacMessage(const std::string& message, std::string* signature, size_t mac_length);
-
- void VerifyMessage(const std::string& message, const std::string& signature,
- keymaster_digest_t digest);
- void VerifyMessage(const std::string& message, const std::string& signature,
- keymaster_digest_t digest, keymaster_padding_t padding);
- void VerifyMac(const std::string& message, const std::string& signature);
-
- std::string EncryptMessage(const std::string& message, keymaster_padding_t padding,
- std::string* generated_nonce = NULL);
- std::string EncryptMessage(const std::string& message, keymaster_digest_t digest,
- keymaster_padding_t padding, std::string* generated_nonce = NULL);
- std::string EncryptMessage(const std::string& message, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding, std::string* generated_nonce = NULL);
- std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
- keymaster_digest_t digest, keymaster_padding_t padding,
- std::string* generated_nonce = NULL);
- std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
- keymaster_block_mode_t block_mode, keymaster_padding_t padding,
- std::string* generated_nonce = NULL);
- std::string EncryptMessageWithParams(const std::string& message,
- const AuthorizationSet& begin_params,
- const AuthorizationSet& update_params,
- AuthorizationSet* output_params);
-
- std::string DecryptMessage(const std::string& ciphertext, keymaster_padding_t padding);
- std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
- keymaster_padding_t padding);
- std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding);
- std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
- keymaster_padding_t padding, const std::string& nonce);
- std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
- keymaster_padding_t padding, const std::string& nonce);
- std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
- keymaster_digest_t digest, keymaster_padding_t padding,
- const std::string& nonce);
- std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
- keymaster_block_mode_t block_mode, keymaster_padding_t padding,
- const std::string& nonce);
-
- void CheckHmacTestVector(const std::string& key, const std::string& message, keymaster_digest_t digest,
- std::string expected_mac);
- void CheckAesOcbTestVector(const std::string& key, const std::string& nonce,
- const std::string& associated_data, const std::string& message,
- const std::string& expected_ciphertext);
- void CheckAesCtrTestVector(const std::string& key, const std::string& nonce,
- const std::string& message, const std::string& expected_ciphertext);
- AuthorizationSet UserAuthParams();
- AuthorizationSet ClientParams();
-
- template <typename T>
- bool ResponseContains(const std::vector<T>& expected, const T* values, size_t len) {
- return expected.size() == len &&
- std::is_permutation(values, values + len, expected.begin());
- }
-
- template <typename T> bool ResponseContains(T expected, const T* values, size_t len) {
- return (len == 1 && *values == expected);
- }
-
- AuthorizationSet hw_enforced();
- AuthorizationSet sw_enforced();
-
- void FreeCharacteristics();
- void FreeKeyBlob();
-
- void corrupt_key_blob();
-
- void set_key_blob(const uint8_t* key, size_t key_length) {
- FreeKeyBlob();
- blob_.key_material = key;
- blob_.key_material_size = key_length;
- }
-
- AuthorizationSet client_params() {
- return AuthorizationSet(client_params_, sizeof(client_params_) / sizeof(client_params_[0]));
- }
-
- private:
- keymaster2_device_t* device_;
- keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
- .data_length = 6};
- keymaster_key_param_t client_params_[1] = {
- Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
-
- uint64_t op_handle_;
-
- keymaster_key_blob_t blob_;
- keymaster_key_characteristics_t characteristics_;
-};
-
-struct Keymaster0CountingWrapper : public keymaster0_device_t {
- explicit Keymaster0CountingWrapper(keymaster0_device_t* device) : device_(device), counter_(0) {
- common = device_->common;
- common.close = counting_close_device;
- client_version = device_->client_version;
- flags = device_->flags;
- context = this;
-
- generate_keypair = counting_generate_keypair;
- import_keypair = counting_import_keypair;
- get_keypair_public = counting_get_keypair_public;
- delete_keypair = counting_delete_keypair;
- delete_all = counting_delete_all;
- sign_data = counting_sign_data;
- verify_data = counting_verify_data;
- }
-
- int count() { return counter_; }
-
- // The blobs generated by the underlying softkeymaster start with "PK#8". Tweak the prefix so
- // they don't get identified as softkeymaster blobs.
- static void munge_blob(uint8_t* blob, size_t blob_length) {
- if (blob && blob_length > 0 && *blob == 'P')
- *blob = 'Q'; // Mind your Ps and Qs!
- }
-
- // Copy and un-modfy the blob. The caller must clean up the return value.
- static uint8_t* unmunge_blob(const uint8_t* blob, size_t blob_length) {
- uint8_t* dup_blob = dup_buffer(blob, blob_length);
- if (dup_blob && blob_length > 0 && *dup_blob == 'Q')
- *dup_blob = 'P';
- return dup_blob;
- }
-
- static keymaster0_device_t* device(const keymaster0_device_t* dev) {
- Keymaster0CountingWrapper* wrapper =
- reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
- return wrapper->device_;
- }
-
- static void increment(const keymaster0_device_t* dev) {
- Keymaster0CountingWrapper* wrapper =
- reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
- wrapper->counter_++;
- }
-
- static int counting_close_device(hw_device_t* dev) {
- keymaster0_device_t* k0_dev = reinterpret_cast<keymaster0_device_t*>(dev);
- increment(k0_dev);
- Keymaster0CountingWrapper* wrapper =
- reinterpret_cast<Keymaster0CountingWrapper*>(k0_dev->context);
- int retval =
- wrapper->device_->common.close(reinterpret_cast<hw_device_t*>(wrapper->device_));
- delete wrapper;
- return retval;
- }
-
- static int counting_generate_keypair(const struct keymaster0_device* dev,
- const keymaster_keypair_t key_type, const void* key_params,
- uint8_t** key_blob, size_t* key_blob_length) {
- increment(dev);
- int result = device(dev)->generate_keypair(device(dev), key_type, key_params, key_blob,
- key_blob_length);
- if (result == 0)
- munge_blob(*key_blob, *key_blob_length);
- return result;
- }
-
- static int counting_import_keypair(const struct keymaster0_device* dev, const uint8_t* key,
- const size_t key_length, uint8_t** key_blob,
- size_t* key_blob_length) {
- increment(dev);
- int result =
- device(dev)->import_keypair(device(dev), key, key_length, key_blob, key_blob_length);
- if (result == 0)
- munge_blob(*key_blob, *key_blob_length);
- return result;
- }
-
- static int counting_get_keypair_public(const struct keymaster0_device* dev,
- const uint8_t* key_blob, const size_t key_blob_length,
- uint8_t** x509_data, size_t* x509_data_length) {
- increment(dev);
- std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
- return device(dev)->get_keypair_public(device(dev), dup_blob.get(), key_blob_length,
- x509_data, x509_data_length);
- }
-
- static int counting_delete_keypair(const struct keymaster0_device* dev, const uint8_t* key_blob,
- const size_t key_blob_length) {
- increment(dev);
- if (key_blob && key_blob_length > 0)
- EXPECT_EQ('Q', *key_blob);
- if (device(dev)->delete_keypair) {
- std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
- return device(dev)->delete_keypair(device(dev), dup_blob.get(), key_blob_length);
- }
- return 0;
- }
-
- static int counting_delete_all(const struct keymaster0_device* dev) {
- increment(dev);
- if (device(dev)->delete_all)
- return device(dev)->delete_all(device(dev));
- return 0;
- }
-
- static int counting_sign_data(const struct keymaster0_device* dev, const void* signing_params,
- const uint8_t* key_blob, const size_t key_blob_length,
- const uint8_t* data, const size_t data_length,
- uint8_t** signed_data, size_t* signed_data_length) {
- increment(dev);
- std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
- return device(dev)->sign_data(device(dev), signing_params, dup_blob.get(), key_blob_length,
- data, data_length, signed_data, signed_data_length);
- }
-
- static int counting_verify_data(const struct keymaster0_device* dev, const void* signing_params,
- const uint8_t* key_blob, const size_t key_blob_length,
- const uint8_t* signed_data, const size_t signed_data_length,
- const uint8_t* signature, const size_t signature_length) {
- increment(dev);
- std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
- return device(dev)->verify_data(device(dev), signing_params, dup_blob.get(),
- key_blob_length, signed_data, signed_data_length, signature,
- signature_length);
- }
-
- private:
- keymaster0_device_t* device_;
- int counter_;
-};
-
-/**
- * This function takes a keymaster1_device_t and wraps it in an adapter that supports only
- * KM_DIGEST_SHA_2_256.
- */
-keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device);
-
-} // namespace test
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
diff --git a/unit_test/android_keymaster_utils.h b/unit_test/android_keymaster_utils.h
deleted file mode 100644
index b957dd1..0000000
--- a/unit_test/android_keymaster_utils.h
+++ b/dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2014 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 SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
-
-#include <stdint.h>
-#include <string.h>
-#include <time.h> // for time_t.
-
-#include <UniquePtr.h>
-
-#include <hardware/keymaster_defs.h>
-#include <keymaster/serializable.h>
-
-namespace keymaster {
-
-/**
- * Convert the specified time value into "Java time", which is a signed 64-bit integer representing
- * elapsed milliseconds since Jan 1, 1970.
- */
-inline int64_t java_time(time_t time) {
- // The exact meaning of a time_t value is implementation-dependent. If this code is ported to a
- // platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have
- // to be revised.
- return time * 1000;
-}
-
-/*
- * Array Manipulation functions. This set of templated inline functions provides some nice tools
- * for operating on c-style arrays. C-style arrays actually do have a defined size associated with
- * them, as long as they are not allowed to decay to a pointer. These template methods exploit this
- * to allow size-based array operations without explicitly specifying the size. If passed a pointer
- * rather than an array, they'll fail to compile.
- */
-
-/**
- * Return the size in bytes of the array \p a.
- */
-template <typename T, size_t N> inline size_t array_size(const T(&a)[N]) {
- return sizeof(a);
-}
-
-/**
- * Return the number of elements in array \p a.
- */
-template <typename T, size_t N> inline size_t array_length(const T(&)[N]) {
- return N;
-}
-
-/**
- * Duplicate the array \p a. The memory for the new array is allocated and the caller takes
- * responsibility.
- */
-template <typename T> inline T* dup_array(const T* a, size_t n) {
- T* dup = new (std::nothrow) T[n];
- if (dup)
- for (size_t i = 0; i < n; ++i)
- dup[i] = a[i];
- return dup;
-}
-
-/**
- * Duplicate the array \p a. The memory for the new array is allocated and the caller takes
- * responsibility. Note that the dup is necessarily returned as a pointer, so size is lost. Call
- * array_length() on the original array to discover the size.
- */
-template <typename T, size_t N> inline T* dup_array(const T(&a)[N]) {
- return dup_array(a, N);
-}
-
-/**
- * Duplicate the buffer \p buf. The memory for the new buffer is allocated and the caller takes
- * responsibility.
- */
-uint8_t* dup_buffer(const void* buf, size_t size);
-
-/**
- * Copy the contents of array \p arr to \p dest.
- */
-template <typename T, size_t N> inline void copy_array(const T(&arr)[N], T* dest) {
- for (size_t i = 0; i < N; ++i)
- dest[i] = arr[i];
-}
-
-/**
- * Search array \p a for value \p val, returning true if found. Note that this function is
- * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
- * a concern.
- */
-template <typename T, size_t N> inline bool array_contains(const T(&a)[N], T val) {
- for (size_t i = 0; i < N; ++i) {
- if (a[i] == val) {
- return true;
- }
- }
- return false;
-}
-
-/**
- * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
- * optimized away. This is important because we often need to wipe blocks of sensitive data from
- * memory. As an additional convenience, this implementation avoids writing to NULL pointers.
- */
-#ifdef __clang__
-#define OPTNONE __attribute__((optnone))
-#else // not __clang__
-#define OPTNONE __attribute__((optimize("O0")))
-#endif // not __clang__
-inline OPTNONE void* memset_s(void* s, int c, size_t n) {
- if (!s)
- return s;
- return memset(s, c, n);
-}
-#undef OPTNONE
-
-/**
- * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
- * short-circuit). Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
- * 0 for match and non-zero for non-match.
- */
-int memcmp_s(const void* p1, const void* p2, size_t length);
-
-/**
- * Eraser clears buffers. Construct it with a buffer or object and the destructor will ensure that
- * it is zeroed.
- */
-class Eraser {
- public:
- /* Not implemented. If this gets used, we want a link error. */
- template <typename T> explicit Eraser(T* t);
-
- template <typename T>
- explicit Eraser(T& t)
- : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
-
- template <size_t N> explicit Eraser(uint8_t(&arr)[N]) : buf_(arr), size_(N) {}
-
- Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
- ~Eraser() { memset_s(buf_, 0, size_); }
-
- private:
- Eraser(const Eraser&);
- void operator=(const Eraser&);
-
- uint8_t* buf_;
- size_t size_;
-};
-
-/**
- * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end()
- * methods. This is primarily to facilitate range-based iteration on arrays. It does not copy, nor
- * does it take ownership; it just holds pointers.
- */
-template <typename T> class ArrayWrapper {
- public:
- ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {}
-
- T* begin() { return begin_; }
- T* end() { return end_; }
-
- private:
- T* begin_;
- T* end_;
-};
-
-/**
- * Convert any unsigned integer from network to host order. We implement this here rather than
- * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most
- * efficient implementation, but the compiler should unroll the loop and tighten it up.
- */
-template <typename T> T ntoh(T t) {
- const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(&t);
- T retval = 0;
- for (size_t i = 0; i < sizeof(t); ++i) {
- retval <<= 8;
- retval |= byte_ptr[i];
- }
- return retval;
-}
-
-/**
- * Convert any unsigned integer from host to network order. We implement this here rather than
- * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most
- * efficient implementation, but the compiler should unroll the loop and tighten it up.
- */
-template <typename T> T hton(T t) {
- T retval;
- uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(&retval);
- for (size_t i = sizeof(t); i > 0; --i) {
- byte_ptr[i - 1] = t & 0xFF;
- t >>= 8;
- }
- return retval;
-}
-
-/**
- * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t. It manages its
- * own memory, which makes avoiding memory leaks much easier.
- */
-struct KeymasterKeyBlob : public keymaster_key_blob_t {
- KeymasterKeyBlob() {
- key_material = nullptr;
- key_material_size = 0;
- }
-
- KeymasterKeyBlob(const uint8_t* data, size_t size) {
- key_material_size = 0;
- key_material = dup_buffer(data, size);
- if (key_material)
- key_material_size = size;
- }
-
- explicit KeymasterKeyBlob(size_t size) {
- key_material_size = 0;
- key_material = new (std::nothrow) uint8_t[size];
- if (key_material)
- key_material_size = size;
- }
-
- explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) {
- key_material_size = 0;
- key_material = dup_buffer(blob.key_material, blob.key_material_size);
- if (key_material)
- key_material_size = blob.key_material_size;
- }
-
- KeymasterKeyBlob(const KeymasterKeyBlob& blob) {
- key_material_size = 0;
- key_material = dup_buffer(blob.key_material, blob.key_material_size);
- if (key_material)
- key_material_size = blob.key_material_size;
- }
-
- void operator=(const KeymasterKeyBlob& blob) {
- Clear();
- key_material = dup_buffer(blob.key_material, blob.key_material_size);
- key_material_size = blob.key_material_size;
- }
-
- ~KeymasterKeyBlob() { Clear(); }
-
- const uint8_t* begin() const { return key_material; }
- const uint8_t* end() const { return key_material + key_material_size; }
-
- void Clear() {
- memset_s(const_cast<uint8_t*>(key_material), 0, key_material_size);
- delete[] key_material;
- key_material = nullptr;
- key_material_size = 0;
- }
-
- const uint8_t* Reset(size_t new_size) {
- Clear();
- key_material = new (std::nothrow) uint8_t[new_size];
- if (key_material)
- key_material_size = new_size;
- return key_material;
- }
-
- // The key_material in keymaster_key_blob_t is const, which is the right thing in most
- // circumstances, but occasionally we do need to write into it. This method exposes a non-const
- // version of the pointer. Use sparingly.
- uint8_t* writable_data() { return const_cast<uint8_t*>(key_material); }
-
- keymaster_key_blob_t release() {
- keymaster_key_blob_t tmp = {key_material, key_material_size};
- key_material = nullptr;
- key_material_size = 0;
- return tmp;
- }
-
- size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; }
- uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const {
- return append_size_and_data_to_buf(buf, end, key_material, key_material_size);
- }
-
- bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
- Clear();
- UniquePtr<uint8_t[]> tmp;
- if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) {
- key_material = nullptr;
- key_material_size = 0;
- return false;
- }
- key_material = tmp.release();
- return true;
- }
-};
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/unit_test/attestation_record.cpp b/unit_test/attestation_record.cpp
deleted file mode 100644
index 8ba5a8a..0000000
--- a/unit_test/attestation_record.cpp
+++ b/dev/null
@@ -1,690 +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.
- */
-
-#include "attestation_record.h"
-
-#include <assert.h>
-
-#include <openssl/asn1t.h>
-
-#include "openssl_err.h"
-#include "openssl_utils.h"
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_context.h>
-
-namespace keymaster {
-
-struct stack_st_ASN1_TYPE_Delete {
- void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
-};
-
-struct ASN1_STRING_Delete {
- void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
-};
-
-struct ASN1_TYPE_Delete {
- void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
-};
-
-#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
-
-typedef struct km_root_of_trust {
- ASN1_OCTET_STRING* verified_boot_key;
- ASN1_BOOLEAN* device_locked;
- ASN1_ENUMERATED* verified_boot_state;
-} KM_ROOT_OF_TRUST;
-
-ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
-} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
-IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
-
-typedef struct km_auth_list {
- ASN1_INTEGER_SET* purpose;
- ASN1_INTEGER* algorithm;
- ASN1_INTEGER* key_size;
- ASN1_INTEGER_SET* digest;
- ASN1_INTEGER_SET* padding;
- ASN1_INTEGER_SET* kdf;
- ASN1_INTEGER* ec_curve;
- ASN1_INTEGER* rsa_public_exponent;
- ASN1_INTEGER* active_date_time;
- ASN1_INTEGER* origination_expire_date_time;
- ASN1_INTEGER* usage_expire_date_time;
- ASN1_NULL* no_auth_required;
- ASN1_INTEGER* user_auth_type;
- ASN1_INTEGER* auth_timeout;
- ASN1_NULL* allow_while_on_body;
- ASN1_NULL* all_applications;
- ASN1_OCTET_STRING* application_id;
- ASN1_INTEGER* creation_date_time;
- ASN1_INTEGER* origin;
- ASN1_NULL* rollback_resistant;
- KM_ROOT_OF_TRUST* root_of_trust;
- ASN1_INTEGER* os_version;
- ASN1_INTEGER* os_patchlevel;
-} KM_AUTH_LIST;
-
-ASN1_SEQUENCE(KM_AUTH_LIST) = {
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
- TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
- TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
- TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
- TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
- TAG_CREATION_DATETIME.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
-} ASN1_SEQUENCE_END(KM_AUTH_LIST);
-IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
-
-typedef struct km_key_description {
- ASN1_INTEGER* attestation_version;
- ASN1_ENUMERATED* attestation_security_level;
- ASN1_INTEGER* keymaster_version;
- ASN1_ENUMERATED* keymaster_security_level;
- ASN1_OCTET_STRING* attestation_challenge;
- KM_AUTH_LIST* software_enforced;
- KM_AUTH_LIST* tee_enforced;
- ASN1_INTEGER* unique_id;
-} KM_KEY_DESCRIPTION;
-
-ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
- ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
-} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
-IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
-
-struct KM_AUTH_LIST_Delete {
- void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); }
-};
-
-struct KM_KEY_DESCRIPTION_Delete {
- void operator()(KM_KEY_DESCRIPTION* p) { KM_KEY_DESCRIPTION_free(p); }
-};
-
-static uint32_t get_uint32_value(const keymaster_key_param_t& param) {
- switch (keymaster_tag_get_type(param.tag)) {
- case KM_ENUM:
- case KM_ENUM_REP:
- return param.enumerated;
- case KM_UINT:
- case KM_UINT_REP:
- return param.integer;
- default:
- assert(false);
- return 0xFFFFFFFF;
- }
-}
-
-// Insert value in either the dest_integer or the dest_integer_set, whichever is provided.
-static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest_integer,
- ASN1_INTEGER_SET** dest_integer_set) {
- assert((dest_integer == nullptr) ^ (dest_integer_set == nullptr));
- assert(value);
-
- if (dest_integer_set) {
- if (!*dest_integer_set)
- *dest_integer_set = sk_ASN1_INTEGER_new_null();
- if (!*dest_integer_set)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- if (!sk_ASN1_INTEGER_push(*dest_integer_set, value))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return KM_ERROR_OK;
-
- } else if (dest_integer) {
- if (*dest_integer)
- ASN1_INTEGER_free(*dest_integer);
- *dest_integer = value;
- return KM_ERROR_OK;
- }
-
- assert(false); // Should never get here.
- return KM_ERROR_OK;
-}
-
-// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
-// record.
-static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
- assert(record);
-
- if (auth_list.empty())
- return KM_ERROR_OK;
-
- for (auto entry : auth_list) {
-
- ASN1_INTEGER_SET** integer_set = nullptr;
- ASN1_INTEGER** integer_ptr = nullptr;
- ASN1_OCTET_STRING** string_ptr = nullptr;
- ASN1_NULL** bool_ptr = nullptr;
-
- switch (entry.tag) {
-
- /* Ignored tags */
- case KM_TAG_INVALID:
- case KM_TAG_ASSOCIATED_DATA:
- case KM_TAG_NONCE:
- case KM_TAG_AUTH_TOKEN:
- case KM_TAG_MAC_LENGTH:
- case KM_TAG_ALL_USERS:
- case KM_TAG_USER_ID:
- case KM_TAG_USER_SECURE_ID:
- case KM_TAG_EXPORTABLE:
- case KM_TAG_RESET_SINCE_ID_ROTATION:
- case KM_TAG_ATTESTATION_CHALLENGE:
- case KM_TAG_BLOCK_MODE:
- case KM_TAG_CALLER_NONCE:
- case KM_TAG_MIN_MAC_LENGTH:
- case KM_TAG_ECIES_SINGLE_HASH_MODE:
- case KM_TAG_INCLUDE_UNIQUE_ID:
- case KM_TAG_BLOB_USAGE_REQUIREMENTS:
- case KM_TAG_BOOTLOADER_ONLY:
- case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
- case KM_TAG_MAX_USES_PER_BOOT:
- case KM_TAG_APPLICATION_DATA:
- case KM_TAG_UNIQUE_ID:
- case KM_TAG_ROOT_OF_TRUST:
- continue;
-
- /* Non-repeating enumerations */
- case KM_TAG_ALGORITHM:
- integer_ptr = &record->algorithm;
- break;
- case KM_TAG_EC_CURVE:
- integer_ptr = &record->ec_curve;
- break;
- case KM_TAG_USER_AUTH_TYPE:
- integer_ptr = &record->user_auth_type;
- break;
- case KM_TAG_ORIGIN:
- integer_ptr = &record->origin;
- break;
-
- /* Repeating enumerations */
- case KM_TAG_PURPOSE:
- integer_set = &record->purpose;
- break;
- case KM_TAG_PADDING:
- integer_set = &record->padding;
- break;
- case KM_TAG_DIGEST:
- integer_set = &record->digest;
- break;
- case KM_TAG_KDF:
- integer_set = &record->kdf;
- break;
-
- /* Non-repeating unsigned integers */
- case KM_TAG_KEY_SIZE:
- integer_ptr = &record->key_size;
- break;
- case KM_TAG_AUTH_TIMEOUT:
- integer_ptr = &record->auth_timeout;
- break;
- case KM_TAG_OS_VERSION:
- integer_ptr = &record->os_version;
- break;
- case KM_TAG_OS_PATCHLEVEL:
- integer_ptr = &record->os_patchlevel;
- break;
-
- /* Non-repeating long unsigned integers */
- case KM_TAG_RSA_PUBLIC_EXPONENT:
- integer_ptr = &record->rsa_public_exponent;
- break;
-
- /* Dates */
- case KM_TAG_ACTIVE_DATETIME:
- integer_ptr = &record->active_date_time;
- break;
- case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
- integer_ptr = &record->origination_expire_date_time;
- break;
- case KM_TAG_USAGE_EXPIRE_DATETIME:
- integer_ptr = &record->usage_expire_date_time;
- break;
- case KM_TAG_CREATION_DATETIME:
- integer_ptr = &record->creation_date_time;
- break;
-
- /* Booleans */
- case KM_TAG_NO_AUTH_REQUIRED:
- bool_ptr = &record->no_auth_required;
- break;
- case KM_TAG_ALL_APPLICATIONS:
- bool_ptr = &record->all_applications;
- break;
- case KM_TAG_ROLLBACK_RESISTANT:
- bool_ptr = &record->rollback_resistant;
- break;
- case KM_TAG_ALLOW_WHILE_ON_BODY:
- bool_ptr = &record->allow_while_on_body;
- break;
-
- /* Byte arrays*/
- case KM_TAG_APPLICATION_ID:
- string_ptr = &record->application_id;
- break;
- default:
- break;
- }
-
- keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag);
- switch (type) {
- case KM_ENUM:
- case KM_ENUM_REP:
- case KM_UINT:
- case KM_UINT_REP: {
- assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
- (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
-
- UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
- if (!value.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry)))
- return TranslateLastOpenSslError();
-
- insert_integer(value.release(), integer_ptr, integer_set);
- break;
- }
-
- case KM_ULONG:
- case KM_ULONG_REP:
- case KM_DATE: {
- assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
- (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
-
- UniquePtr<BIGNUM, BIGNUM_Delete> bn_value(BN_new());
- if (!bn_value.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- if (type == KM_DATE) {
- if (!BN_set_u64(bn_value.get(), entry.date_time)) {
- return TranslateLastOpenSslError();
- }
- } else {
- if (!BN_set_u64(bn_value.get(), entry.long_integer)) {
- return TranslateLastOpenSslError();
- }
- }
-
- UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
- BN_to_ASN1_INTEGER(bn_value.get(), nullptr));
- if (!value.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- insert_integer(value.release(), integer_ptr, integer_set);
- break;
- }
-
- case KM_BOOL:
- assert(bool_ptr);
- if (!*bool_ptr)
- *bool_ptr = ASN1_NULL_new();
- if (!*bool_ptr)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- break;
-
- /* Byte arrays*/
- case KM_BYTES:
- assert(string_ptr);
- if (!*string_ptr)
- *string_ptr = ASN1_OCTET_STRING_new();
- if (!*string_ptr)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length))
- return TranslateLastOpenSslError();
- break;
-
- default:
- return KM_ERROR_UNIMPLEMENTED;
- }
- }
-
- keymaster_ec_curve_t ec_curve;
- uint32_t key_size;
- if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) && //
- !auth_list.Contains(TAG_EC_CURVE) && //
- auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) {
- // This must be a keymaster1 key. It's an EC key with no curve. Insert the curve.
-
- keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve);
- if (error != KM_ERROR_OK)
- return error;
-
- UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
- if (!value.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- if (!ASN1_INTEGER_set(value.get(), ec_curve))
- return TranslateLastOpenSslError();
-
- insert_integer(value.release(), &record->ec_curve, nullptr);
- }
-
- return KM_ERROR_OK;
-}
-
-// Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and
-// tee_enforced.
-keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
- const AuthorizationSet& sw_enforced,
- const AuthorizationSet& tee_enforced,
- const KeymasterContext& context,
- UniquePtr<uint8_t[]>* asn1_key_desc,
- size_t* asn1_key_desc_len) {
- assert(asn1_key_desc && asn1_key_desc_len);
-
- UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new());
- if (!key_desc.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- keymaster_security_level_t keymaster_security_level;
- uint32_t keymaster_version = UINT32_MAX;
- if (tee_enforced.empty()) {
- // Software key.
- keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
- keymaster_version = 2;
- } else {
- keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
- switch (context.GetSecurityLevel()) {
- case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
- // We're running in a TEE, so the key is KM2.
- keymaster_version = 2;
- break;
-
- case KM_SECURITY_LEVEL_SOFTWARE:
- // We're running in software, wrapping some KM hardware. Is it KM0 or KM1? KM1 keys
- // have the purpose in the tee_enforced list. It's possible that a key could be created
- // without a purpose, which would fool this test into reporting it's a KM0 key. That
- // corner case doesn't matter much, because purpose-less keys are not usable anyway.
- // Also, KM1 TEEs should disappear rapidly.
- keymaster_version = tee_enforced.Contains(TAG_PURPOSE) ? 1 : 0;
- break;
- }
-
- if (keymaster_version == UINT32_MAX)
- return KM_ERROR_UNKNOWN_ERROR;
- }
-
- if (!ASN1_INTEGER_set(key_desc->attestation_version, 1) ||
- !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) ||
- !ASN1_INTEGER_set(key_desc->keymaster_version, keymaster_version) ||
- !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level))
- return TranslateLastOpenSslError();
-
- keymaster_blob_t attestation_challenge = {nullptr, 0};
- if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge))
- return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
- if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data,
- attestation_challenge.data_length))
- return TranslateLastOpenSslError();
-
- keymaster_error_t error = build_auth_list(sw_enforced, key_desc->software_enforced);
- if (error != KM_ERROR_OK)
- return error;
-
- error = build_auth_list(tee_enforced, key_desc->tee_enforced);
- if (error != KM_ERROR_OK)
- return error;
-
- // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID. If we don't have hardware we can't
- // generate unique IDs.
- if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) {
- uint64_t creation_datetime;
- // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced,
- // since this implementation has no secure wall clock.
- if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) {
- LOG_E("Unique ID cannot be created without creation datetime", 0);
- return KM_ERROR_INVALID_KEY_BLOB;
- }
-
- keymaster_blob_t application_id = {nullptr, 0};
- sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
-
- Buffer unique_id;
- error = context.GenerateUniqueId(
- creation_datetime, application_id,
- attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id);
- if (error != KM_ERROR_OK)
- return error;
-
- key_desc->unique_id = ASN1_OCTET_STRING_new();
- if (!key_desc->unique_id ||
- !ASN1_OCTET_STRING_set(key_desc->unique_id, unique_id.peek_read(),
- unique_id.available_read()))
- return TranslateLastOpenSslError();
- }
-
- int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
- if (len < 0)
- return TranslateLastOpenSslError();
- *asn1_key_desc_len = len;
- asn1_key_desc->reset(new uint8_t[*asn1_key_desc_len]);
- if (!asn1_key_desc->get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- uint8_t* p = asn1_key_desc->get();
- len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), &p);
- if (len < 0)
- return TranslateLastOpenSslError();
-
- return KM_ERROR_OK;
-}
-
-// Copy all enumerated values with the specified tag from stack to auth_list.
-static bool get_repeated_enums(const stack_st_ASN1_INTEGER* stack, keymaster_tag_t tag,
- AuthorizationSet* auth_list) {
- assert(keymaster_tag_get_type(tag) == KM_ENUM_REP);
- for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
- if (!auth_list->push_back(
- keymaster_param_enum(tag, ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))))
- return false;
- }
- return true;
-}
-
-// Add the specified integer tag/value pair to auth_list.
-template <keymaster_tag_type_t Type, keymaster_tag_t Tag, typename KeymasterEnum>
-static bool get_enum(const ASN1_INTEGER* asn1_int, TypedEnumTag<Type, Tag, KeymasterEnum> tag,
- AuthorizationSet* auth_list) {
- if (!asn1_int)
- return true;
- return auth_list->push_back(tag, static_cast<KeymasterEnum>(ASN1_INTEGER_get(asn1_int)));
-}
-
-// Add the specified ulong tag/value pair to auth_list.
-static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag,
- AuthorizationSet* auth_list) {
- if (!asn1_int)
- return true;
- UniquePtr<BIGNUM, BIGNUM_Delete> bn(ASN1_INTEGER_to_BN(asn1_int, nullptr));
- if (!bn.get())
- return false;
- uint64_t ulong = BN_get_word(bn.get());
- return auth_list->push_back(keymaster_param_long(tag, ulong));
-}
-
-// Extract the values from the specified ASN.1 record and place them in auth_list.
-static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
- AuthorizationSet* auth_list) {
- if (!record)
- return KM_ERROR_OK;
-
- // Purpose
- if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Algorithm
- if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Key size
- if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Digest
- if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Padding
- if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // EC curve
- if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // RSA public exponent
- if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Active date time
- if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Origination expire date time
- if (!get_ulong(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME,
- auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Usage Expire date time
- if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // No auth required
- if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // User auth type
- if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Auth timeout
- if (record->auth_timeout &&
- !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // All applications
- if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Application ID
- if (record->application_id &&
- !auth_list->push_back(TAG_APPLICATION_ID, record->application_id->data,
- record->application_id->length))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Creation date time
- if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Origin
- if (!get_enum(record->origin, TAG_ORIGIN, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Rollback resistant
- if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Root of trust
- if (record->root_of_trust) {
- KM_ROOT_OF_TRUST* rot = record->root_of_trust;
- if (!rot->verified_boot_key)
- return KM_ERROR_INVALID_KEY_BLOB;
-
- // Other root of trust fields are not mapped to auth set entries.
- }
-
- // OS Version
- if (record->os_version &&
- !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // OS Patch level
- if (record->os_patchlevel &&
- !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- return KM_ERROR_OK;
-}
-
-// Parse the DER-encoded attestation record, placing the results in keymaster_version,
-// attestation_challenge, software_enforced, tee_enforced and unique_id.
-keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
- uint32_t* attestation_version, //
- keymaster_security_level_t* attestation_security_level,
- uint32_t* keymaster_version,
- keymaster_security_level_t* keymaster_security_level,
- keymaster_blob_t* attestation_challenge,
- AuthorizationSet* software_enforced,
- AuthorizationSet* tee_enforced,
- keymaster_blob_t* unique_id) {
- const uint8_t* p = asn1_key_desc;
- UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record(
- d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
- if (!record.get())
- return TranslateLastOpenSslError();
-
- *attestation_version = ASN1_INTEGER_get(record->attestation_version);
- *attestation_security_level = static_cast<keymaster_security_level_t>(
- ASN1_ENUMERATED_get(record->attestation_security_level));
- *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
- *keymaster_security_level = static_cast<keymaster_security_level_t>(
- ASN1_ENUMERATED_get(record->keymaster_security_level));
-
- attestation_challenge->data =
- dup_buffer(record->attestation_challenge->data, record->attestation_challenge->length);
- attestation_challenge->data_length = record->attestation_challenge->length;
-
- unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length);
- unique_id->data_length = record->unique_id->length;
-
- keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
- if (error != KM_ERROR_OK)
- return error;
-
- return extract_auth_list(record->tee_enforced, tee_enforced);
-}
-
-} // namepace keymaster
diff --git a/unit_test/attestation_record.h b/unit_test/attestation_record.h
deleted file mode 100644
index 64acabc..0000000
--- a/unit_test/attestation_record.h
+++ b/dev/null
@@ -1,62 +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 SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
-#define SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
-
-#include <hardware/keymaster_defs.h>
-
-#include <keymaster/authorization_set.h>
-
-namespace keymaster {
-
-class KeymasterContext;
-
-/**
- * The OID for Android attestation records. For the curious, it breaks down as follows:
- *
- * 1 = ISO
- * 3 = org
- * 6 = DoD (Huh? OIDs are weird.)
- * 1 = IANA
- * 4 = Private
- * 1 = Enterprises
- * 11129 = Google
- * 2 = Google security
- * 1 = certificate extension
- * 17 = Android attestation extension.
- */
-static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
-
-keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
- const AuthorizationSet& software_enforced,
- const AuthorizationSet& tee_enforced,
- const KeymasterContext& context,
- UniquePtr<uint8_t[]>* asn1_key_desc,
- size_t* asn1_key_desc_len);
-
-keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
- uint32_t* attestation_version, //
- keymaster_security_level_t* attestation_security_level,
- uint32_t* keymaster_version,
- keymaster_security_level_t* keymaster_security_level,
- keymaster_blob_t* attestation_challenge,
- AuthorizationSet* software_enforced,
- AuthorizationSet* tee_enforced,
- keymaster_blob_t* unique_id);
-}
-
-#endif // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/unit_test/attestation_record_test.cpp b/unit_test/attestation_record_test.cpp
deleted file mode 100644
index 1cf8630..0000000
--- a/unit_test/attestation_record_test.cpp
+++ b/dev/null
@@ -1,145 +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.
- */
-
-#include <fstream>
-
-#include <gtest/gtest.h>
-
-#include <keymaster/keymaster_context.h>
-
-#include "android_keymaster_test_utils.h"
-#include "attestation_record.h"
-
-#include <keymaster/keymaster_context.h>
-
-namespace keymaster {
-namespace test {
-
-class TestContext : public KeymasterContext {
- public:
- keymaster_security_level_t GetSecurityLevel() const override {
- return KM_SECURITY_LEVEL_SOFTWARE;
- }
- keymaster_error_t SetSystemVersion(uint32_t /* os_version */,
- uint32_t /* os_patchlevel */) override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override {
- *os_version = 0;
- *os_patchlevel = 0;
- }
- KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override {
- return nullptr;
- }
- OperationFactory* GetOperationFactory(keymaster_algorithm_t /* algorithm */,
- keymaster_purpose_t /* purpose */) const override {
- return nullptr;
- }
- keymaster_algorithm_t* GetSupportedAlgorithms(size_t* /* algorithms_count */) const override {
- return nullptr;
- }
- keymaster_error_t CreateKeyBlob(const AuthorizationSet& /* key_description */,
- keymaster_key_origin_t /* origin */,
- const KeymasterKeyBlob& /* key_material */,
- KeymasterKeyBlob* /* blob */,
- AuthorizationSet* /* hw_enforced */,
- AuthorizationSet* /* sw_enforced */) const override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& /* key_to_upgrade */,
- const AuthorizationSet& /* upgrade_params */,
- KeymasterKeyBlob* /* upgraded_key */) const override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */,
- const AuthorizationSet& /* additional_params */,
- KeymasterKeyBlob* /* key_material */,
- AuthorizationSet* /* hw_enforced */,
- AuthorizationSet* /* sw_enforced */) const override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t AddRngEntropy(const uint8_t* /* buf */, size_t /* length */) const override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t GenerateRandom(uint8_t* /* buf */, size_t /* length */) const override {
- return KM_ERROR_UNIMPLEMENTED;
- }
- KeymasterEnforcement* enforcement_policy() { return nullptr; }
- EVP_PKEY* AttestationKey(keymaster_algorithm_t /* algorithm */,
- keymaster_error_t* /* error */) const override {
- return nullptr;
- }
- keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t /* algorithm */,
- keymaster_error_t* /* error */) const override {
- return nullptr;
- }
- keymaster_error_t GenerateUniqueId(uint64_t /* creation_date_time */,
- const keymaster_blob_t& /* application_id */,
- bool /* reset_since_rotation */, Buffer* unique_id) const {
- // Finally, the reason for defining this class:
- unique_id->Reinitialize("foo", 3);
- return KM_ERROR_OK;
- }
-};
-
-TEST(AttestTest, Simple) {
- AuthorizationSet hw_set(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
- .Digest(KM_DIGEST_SHA_2_256)
- .Digest(KM_DIGEST_SHA_2_384)
- .Authorization(TAG_OS_VERSION, 60000)
- .Authorization(TAG_OS_PATCHLEVEL, 201512)
- .Authorization(TAG_APPLICATION_ID, "bar", 3));
- AuthorizationSet sw_set(AuthorizationSetBuilder().Authorization(TAG_ACTIVE_DATETIME, 10));
-
- UniquePtr<uint8_t[]> asn1;
- size_t asn1_len;
- AuthorizationSet attest_params(
- AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE, "hello", 5));
- EXPECT_EQ(KM_ERROR_OK, build_attestation_record(attest_params, sw_set, hw_set, TestContext(),
- &asn1, &asn1_len));
- EXPECT_GT(asn1_len, 0U);
-
- std::ofstream output("attest.der",
- std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
- if (output)
- output.write(reinterpret_cast<const char*>(asn1.get()), asn1_len);
- output.close();
-
- AuthorizationSet parsed_hw_set;
- AuthorizationSet parsed_sw_set;
- uint32_t attestation_version;
- uint32_t keymaster_version;
- keymaster_security_level_t attestation_security_level;
- keymaster_security_level_t keymaster_security_level;
- keymaster_blob_t attestation_challenge = {};
- keymaster_blob_t unique_id = {};
- EXPECT_EQ(KM_ERROR_OK,
- parse_attestation_record(asn1.get(), asn1_len, &attestation_version,
- &attestation_security_level, &keymaster_version,
- &keymaster_security_level, &attestation_challenge,
- &parsed_sw_set, &parsed_hw_set, &unique_id));
-
- hw_set.Sort();
- sw_set.Sort();
- parsed_hw_set.Sort();
- parsed_sw_set.Sort();
- EXPECT_EQ(hw_set, parsed_hw_set);
- EXPECT_EQ(sw_set, parsed_sw_set);
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/authorization_set_test.cpp b/unit_test/authorization_set_test.cpp
deleted file mode 100644
index f3f4412..0000000
--- a/unit_test/authorization_set_test.cpp
+++ b/dev/null
@@ -1,745 +0,0 @@
-/*
- * Copyright (C) 2014 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 <keymaster/authorization_set.h>
-#include <keymaster/android_keymaster_utils.h>
-
-#include "android_keymaster_test_utils.h"
-
-namespace keymaster {
-
-namespace test {
-
-TEST(Construction, ListProvided) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
- Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
- Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
- Authorization(TAG_AUTH_TIMEOUT, 300),
- };
- AuthorizationSet set(params, array_length(params));
- EXPECT_EQ(8U, set.size());
-}
-
-TEST(Construction, Copy) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
- Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
- Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
- Authorization(TAG_AUTH_TIMEOUT, 300),
- };
- AuthorizationSet set(params, array_length(params));
- AuthorizationSet set2(set);
- EXPECT_EQ(set, set2);
-}
-
-TEST(Construction, NullProvided) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- };
-
- AuthorizationSet set1(params, 0);
- EXPECT_EQ(0U, set1.size());
- EXPECT_EQ(AuthorizationSet::OK, set1.is_valid());
-
- AuthorizationSet set2(reinterpret_cast<keymaster_key_param_t*>(NULL), array_length(params));
- EXPECT_EQ(0U, set2.size());
- EXPECT_EQ(AuthorizationSet::OK, set2.is_valid());
-}
-
-TEST(Lookup, NonRepeated) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- EXPECT_EQ(8U, set.size());
-
- int pos = set.find(TAG_ALGORITHM);
- ASSERT_NE(-1, pos);
- EXPECT_EQ(KM_TAG_ALGORITHM, set[pos].tag);
- EXPECT_EQ(KM_ALGORITHM_RSA, set[pos].enumerated);
-
- pos = set.find(TAG_MAC_LENGTH);
- EXPECT_EQ(-1, pos);
-
- uint32_t int_val = 0;
- EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &int_val));
- EXPECT_EQ(7U, int_val);
-
- keymaster_blob_t blob_val;
- EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &blob_val));
- EXPECT_EQ(6U, blob_val.data_length);
- EXPECT_EQ(0, memcmp(blob_val.data, "my_app", 6));
-}
-
-TEST(Lookup, Repeated) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_SECURE_ID, 47727)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
- EXPECT_EQ(9U, set.size());
-
- int pos = set.find(TAG_PURPOSE);
- ASSERT_FALSE(pos == -1);
- EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
- EXPECT_EQ(KM_PURPOSE_SIGN, set[pos].enumerated);
-
- pos = set.find(TAG_PURPOSE, pos);
- EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
- EXPECT_EQ(KM_PURPOSE_VERIFY, set[pos].enumerated);
-
- EXPECT_EQ(-1, set.find(TAG_PURPOSE, pos));
-
- pos = set.find(TAG_USER_SECURE_ID, pos);
- EXPECT_EQ(KM_TAG_USER_SECURE_ID, set[pos].tag);
- EXPECT_EQ(47727U, set[pos].long_integer);
-}
-
-TEST(Lookup, Indexed) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
- EXPECT_EQ(8U, set.size());
-
- EXPECT_EQ(KM_TAG_PURPOSE, set[0].tag);
- EXPECT_EQ(KM_PURPOSE_SIGN, set[0].enumerated);
-
- // Lookup beyond end doesn't work, just returns zeros, but doens't blow up either (verify by
- // running under valgrind).
- EXPECT_EQ(KM_TAG_INVALID, set[10].tag);
-}
-
-TEST(Serialization, RoundTrip) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_USER_SECURE_ID, 47727)
- .Authorization(TAG_AUTH_TIMEOUT, 300)
- .Authorization(TAG_ALL_USERS)
- .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
- .Authorization(TAG_ACTIVE_DATETIME, 10));
-
- size_t size = set.SerializedSize();
- EXPECT_TRUE(size > 0);
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
- AuthorizationSet deserialized(buf.get(), size);
-
- EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
- EXPECT_EQ(set, deserialized);
-
- int pos = deserialized.find(TAG_APPLICATION_ID);
- ASSERT_NE(-1, pos);
- EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
- EXPECT_EQ(6U, deserialized[pos].blob.data_length);
- EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
-}
-
-TEST(Deserialization, Deserialize) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- size_t size = set.SerializedSize();
- EXPECT_TRUE(size > 0);
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
- AuthorizationSet deserialized;
- const uint8_t* p = buf.get();
- EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
- EXPECT_EQ(p, buf.get() + size);
-
- EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
-
- EXPECT_EQ(set.size(), deserialized.size());
- for (size_t i = 0; i < set.size(); ++i) {
- EXPECT_EQ(set[i].tag, deserialized[i].tag);
- }
-
- int pos = deserialized.find(TAG_APPLICATION_ID);
- ASSERT_NE(-1, pos);
- EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
- EXPECT_EQ(6U, deserialized[pos].blob.data_length);
- EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
-}
-
-TEST(Deserialization, TooShortBuffer) {
- uint8_t buf[] = {0, 0, 0};
- AuthorizationSet deserialized(buf, array_length(buf));
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
-
- const uint8_t* p = buf;
- EXPECT_FALSE(deserialized.Deserialize(&p, p + array_length(buf)));
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
-}
-
-TEST(Deserialization, InvalidLengthField) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- size_t size = set.SerializedSize();
- EXPECT_TRUE(size > 0);
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
- *reinterpret_cast<uint32_t*>(buf.get()) = 9;
-
- AuthorizationSet deserialized(buf.get(), size);
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
-
- const uint8_t* p = buf.get();
- EXPECT_FALSE(deserialized.Deserialize(&p, p + size));
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
-}
-
-static uint32_t read_uint32(const uint8_t* buf) {
- uint32_t val;
- memcpy(&val, buf, sizeof(val));
- return val;
-}
-
-static void add_to_uint32(uint8_t* buf, int delta) {
- uint32_t val;
- memcpy(&val, buf, sizeof(val));
- val += delta;
- memcpy(buf, &val, sizeof(val));
-}
-
-TEST(Deserialization, MalformedIndirectData) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_APPLICATION_DATA, "foo", 3));
- size_t size = set.SerializedSize();
-
- UniquePtr<uint8_t[]> buf(new uint8_t[size]);
- EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
-
- // This sucks. This test, as written, requires intimate knowledge of the serialized layout of
- // this particular set, which means it's brittle. But it's important to test that we handle
- // broken serialized data and I can't think of a better way to write this.
- //
- // The contents of buf are:
- //
- // Bytes: Content:
- // 0-3 Length of string data, which is 9.
- // 4-9 "my_app"
- // 10-12 "foo"
- // 13-16 Number of elements, which is 2.
- // 17-20 Length of elements, which is 24.
- // 21-24 First tag, TAG_APPLICATION_ID
- // 25-28 Length of string "my_app", 6
- // 29-32 Offset of string "my_app", 0
- // 33-36 Second tag, TAG_APPLICATION_DATA
- // 37-40 Length of string "foo", 3
- // 41-44 Offset of string "foo", 6
-
- // Check that stuff is where we think.
- EXPECT_EQ('m', buf[4]);
- EXPECT_EQ('f', buf[10]);
- // Length of "my_app"
- EXPECT_EQ(6U, read_uint32(buf.get() + 25));
- // Offset of "my_app"
- EXPECT_EQ(0U, read_uint32(buf.get() + 29));
- // Length of "foo"
- EXPECT_EQ(3U, read_uint32(buf.get() + 37));
- // Offset of "foo"
- EXPECT_EQ(6U, read_uint32(buf.get() + 41));
-
- // Check that deserialization works.
- AuthorizationSet deserialized1(buf.get(), size);
- EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
-
- const uint8_t* p = buf.get();
- EXPECT_TRUE(deserialized1.Deserialize(&p, p + size));
- EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
-
- //
- // Now mess them up in various ways:
- //
-
- // Move "foo" offset so offset + length goes off the end
- add_to_uint32(buf.get() + 41, 1);
- AuthorizationSet deserialized2(buf.get(), size);
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized2.is_valid());
- add_to_uint32(buf.get() + 41, -1);
-
- // Shorten the "my_app" length to make a gap between the blobs.
- add_to_uint32(buf.get() + 25, -1);
- AuthorizationSet deserialized3(buf.get(), size);
- EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized3.is_valid());
- add_to_uint32(buf.get() + 25, 1);
-
- // Extend the "my_app" length to make them overlap, and decrease the "foo" length to keep the
- // total length the same. We don't detect this but should.
- // TODO(swillden): Detect overlaps and holes that leave total size correct.
- add_to_uint32(buf.get() + 25, 1);
- add_to_uint32(buf.get() + 37, -1);
- AuthorizationSet deserialized4(buf.get(), size);
- EXPECT_EQ(AuthorizationSet::OK, deserialized4.is_valid());
-}
-
-TEST(Growable, SuccessfulRoundTrip) {
- AuthorizationSet growable;
- EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
- EXPECT_EQ(1U, growable.size());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)));
- EXPECT_EQ(2U, growable.size());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
- EXPECT_EQ(3U, growable.size());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "data", 4)));
- EXPECT_EQ(4U, growable.size());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "some more data", 14)));
- EXPECT_EQ(5U, growable.size());
-
- size_t serialize_size = growable.SerializedSize();
- UniquePtr<uint8_t[]> serialized(new uint8_t[serialize_size]);
- EXPECT_EQ(serialized.get() + serialize_size,
- growable.Serialize(serialized.get(), serialized.get() + serialize_size));
-
- AuthorizationSet deserialized(serialized.get(), serialize_size);
- EXPECT_EQ(growable, deserialized);
-}
-
-TEST(Growable, InsufficientElemBuf) {
- AuthorizationSet growable;
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- // First insertion fits.
- EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
- EXPECT_EQ(1U, growable.size());
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- // Second does too.
- EXPECT_TRUE(growable.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)));
- EXPECT_EQ(2U, growable.size());
-}
-
-TEST(Growable, InsufficientIndirectBuf) {
- AuthorizationSet growable;
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
- EXPECT_EQ(1U, growable.size());
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "1234567890", 10)));
- EXPECT_EQ(2U, growable.size());
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "1", 1)));
- EXPECT_EQ(3U, growable.size());
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-
- // Can still add another entry without indirect data. Now it's full.
- EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
- EXPECT_EQ(4U, growable.size());
- EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
-}
-
-TEST(Growable, PushBackSets) {
- AuthorizationSetBuilder builder;
- builder.Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_KEY_SIZE, 256)
- .Authorization(TAG_AUTH_TIMEOUT, 300);
-
- AuthorizationSet set1(builder.build());
- AuthorizationSet set2(builder.build());
-
- AuthorizationSet combined;
- EXPECT_TRUE(combined.push_back(set1));
- EXPECT_TRUE(combined.push_back(set2));
- EXPECT_EQ(set1.size() + set2.size(), combined.size());
- EXPECT_EQ(12U, combined.indirect_size());
-}
-
-TEST(GetValue, GetInt) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- uint32_t val;
- EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &val));
- EXPECT_EQ(7U, val);
-
- // Find one that isn't there
- EXPECT_FALSE(set.GetTagValue(TAG_KEY_SIZE, &val));
-}
-
-TEST(GetValue, GetLong) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-
- uint64_t val;
- EXPECT_TRUE(set1.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
- EXPECT_EQ(3U, val);
-
- // Find one that isn't there
- EXPECT_FALSE(set2.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
-}
-
-TEST(GetValue, GetLongRep) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, 8338)
- .Authorization(TAG_USER_SECURE_ID, 4334)
- .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-
- uint64_t val;
- EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 0, &val));
- EXPECT_EQ(8338U, val);
- EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 1, &val));
- EXPECT_EQ(4334U, val);
-
- // Find one that isn't there
- EXPECT_FALSE(set2.GetTagValue(TAG_USER_SECURE_ID, &val));
-}
-
-TEST(GetValue, GetEnum) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- keymaster_algorithm_t val;
- EXPECT_TRUE(set.GetTagValue(TAG_ALGORITHM, &val));
- EXPECT_EQ(KM_ALGORITHM_RSA, val);
-
- // Find one that isn't there
- keymaster_padding_t val2;
- EXPECT_FALSE(set.GetTagValue(TAG_PADDING, &val2));
-}
-
-TEST(GetValue, GetEnumRep) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- keymaster_purpose_t val;
- EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 0, &val));
- EXPECT_EQ(KM_PURPOSE_SIGN, val);
- EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 1, &val));
- EXPECT_EQ(KM_PURPOSE_VERIFY, val);
-
- // Find one that isn't there
- EXPECT_FALSE(set.GetTagValue(TAG_PURPOSE, 2, &val));
-}
-
-TEST(GetValue, GetDate) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- uint64_t val;
- EXPECT_TRUE(set.GetTagValue(TAG_ACTIVE_DATETIME, &val));
- EXPECT_EQ(10U, val);
-
- // Find one that isn't there
- EXPECT_FALSE(set.GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &val));
-}
-
-TEST(GetValue, GetBlob) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_APPLICATION_ID, "my_app", 6)
- .Authorization(TAG_AUTH_TIMEOUT, 300));
-
- keymaster_blob_t val;
- EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &val));
- EXPECT_EQ(6U, val.data_length);
- EXPECT_EQ(0, memcmp(val.data, "my_app", 6));
-
- // Find one that isn't there
- EXPECT_FALSE(set.GetTagValue(TAG_APPLICATION_DATA, &val));
-}
-
-TEST(Deduplication, NoDuplicates) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
- AuthorizationSet copy(set);
-
- EXPECT_EQ(copy, set);
- set.Deduplicate();
- EXPECT_EQ(copy.size(), set.size());
-
- // Sets no longer compare equal, because of ordering (ugh, maybe it should be
- // AuthorizationList, not AuthorizationSet).
- EXPECT_NE(copy, set);
-}
-
-TEST(Deduplication, NoDuplicatesHasInvalid) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_INVALID)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
- AuthorizationSet copy(set);
-
- EXPECT_EQ(copy, set);
- set.Deduplicate();
-
- // Deduplicate should have removed the invalid.
- EXPECT_EQ(copy.size() - 1, set.size());
- EXPECT_NE(copy, set);
-}
-
-TEST(Deduplication, DuplicateEnum) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
- AuthorizationSet copy(set);
-
- EXPECT_EQ(copy, set);
- set.Deduplicate();
- EXPECT_EQ(copy.size() - 2, set.size());
- EXPECT_NE(copy, set);
-}
-
-TEST(Deduplication, DuplicateBlob) {
- AuthorizationSet set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_APPLICATION_DATA, "data", 4)
- .Authorization(TAG_APPLICATION_DATA, "foo", 3)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
- AuthorizationSet copy(set);
-
- EXPECT_EQ(copy, set);
- set.Deduplicate();
- EXPECT_EQ(copy.size() - 3, set.size());
- EXPECT_NE(copy, set);
-
- // The real test here is that valgrind reports no leak.
-}
-
-TEST(Union, Disjoint) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_APPLICATION_DATA, "foo", 3)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
-
- AuthorizationSet expected(AuthorizationSetBuilder()
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4)
- .Authorization(TAG_APPLICATION_DATA, "foo", 3));
-
- set1.Union(set2);
- EXPECT_EQ(expected, set1);
-}
-
-TEST(Union, Overlap) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet expected(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- set1.Union(set2);
- EXPECT_EQ(expected, set1);
-}
-
-TEST(Union, Empty) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet set2;
-
- AuthorizationSet expected(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- set1.Union(set2);
- EXPECT_EQ(expected, set1);
-}
-
-TEST(Difference, Disjoint) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_APPLICATION_DATA, "data", 4)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_USER_ID, 7)
- .Authorization(TAG_APPLICATION_DATA, "foo", 3)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
-
- // Elements are the same as set1, but happen to be in a different order
- AuthorizationSet expected(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- set1.Difference(set2);
- EXPECT_EQ(expected, set1);
-}
-
-TEST(Difference, Overlap) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet set2(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet empty;
- set1.Difference(set2);
- EXPECT_EQ(empty, set1);
- EXPECT_EQ(0U, set1.size());
-}
-
-TEST(Difference, NullSet) {
- AuthorizationSet set1(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- AuthorizationSet set2;
-
- AuthorizationSet expected(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_ACTIVE_DATETIME, 10)
- .Authorization(TAG_APPLICATION_DATA, "data", 4));
-
- set1.Difference(set2);
- EXPECT_EQ(expected, set1);
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/ecies_kem_test.cpp b/unit_test/ecies_kem_test.cpp
deleted file mode 100644
index f653dc0..0000000
--- a/unit_test/ecies_kem_test.cpp
+++ b/dev/null
@@ -1,73 +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.
- */
-
-#include "ecies_kem.h"
-
-#include <gtest/gtest.h>
-#include <openssl/evp.h>
-
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-
-#include "android_keymaster_test_utils.h"
-#include "nist_curve_key_exchange.h"
-
-using std::string;
-
-namespace keymaster {
-namespace test {
-
-StdoutLogger logger;
-
-static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
- KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
-
-/**
- * TestConsistency just tests that the basic key encapsulation hold.
- */
-TEST(EciesKem, TestConsistency) {
- static const uint32_t kKeyLen = 32;
- for (auto& curve : kEcCurves) {
- AuthorizationSet kem_description(AuthorizationSetBuilder()
- .Authorization(TAG_EC_CURVE, curve)
- .Authorization(TAG_KDF, KM_KDF_RFC5869_SHA256)
- .Authorization(TAG_ECIES_SINGLE_HASH_MODE)
- .Authorization(TAG_KEY_SIZE, kKeyLen));
- keymaster_error_t error;
- EciesKem* kem = new EciesKem(kem_description, &error);
- ASSERT_EQ(KM_ERROR_OK, error);
-
- NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
- Buffer peer_public_value;
- ASSERT_TRUE(key_exchange->public_value(&peer_public_value));
-
- Buffer output_clear_key;
- Buffer output_encrypted_key;
- ASSERT_TRUE(kem->Encrypt(peer_public_value, &output_clear_key, &output_encrypted_key));
- ASSERT_EQ(kKeyLen, output_clear_key.available_read());
- ASSERT_EQ(peer_public_value.available_read(), output_encrypted_key.available_read());
-
- Buffer decrypted_clear_key;
- ASSERT_TRUE(
- kem->Decrypt(key_exchange->private_key(), output_encrypted_key, &decrypted_clear_key));
- ASSERT_EQ(kKeyLen, decrypted_clear_key.available_read());
- EXPECT_EQ(0, memcmp(output_clear_key.peek_read(), decrypted_clear_key.peek_read(),
- output_clear_key.available_read()));
- }
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/gtest_main.cpp b/unit_test/gtest_main.cpp
deleted file mode 100644
index 6072749..0000000
--- a/unit_test/gtest_main.cpp
+++ b/dev/null
@@ -1,34 +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 <openssl/engine.h>
-
-int main(int argc, char** argv) {
-#if !defined(OPENSSL_IS_BORINGSSL)
- ERR_load_crypto_strings();
-#endif // not OPENSSL_IS_BORINGSSL
- ::testing::InitGoogleTest(&argc, argv);
- int result = RUN_ALL_TESTS();
-#if !defined(OPENSSL_IS_BORINGSSL)
- // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_thread_state(NULL);
- ERR_free_strings();
-#endif // not OPENSSL_IS_BORINGSSL
- return result;
-}
diff --git a/unit_test/hkdf_test.cpp b/unit_test/hkdf_test.cpp
deleted file mode 100644
index 3d3f092..0000000
--- a/unit_test/hkdf_test.cpp
+++ b/dev/null
@@ -1,78 +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.
- */
-
-#include "hkdf.h"
-
-#include <gtest/gtest.h>
-#include <string.h>
-
-#include "android_keymaster_test_utils.h"
-
-using std::string;
-
-namespace keymaster {
-namespace test {
-
-struct HkdfTest {
- const char* key_hex;
- const char* salt_hex;
- const char* info_hex;
- const char* output_hex;
-};
-
-// These test cases are taken from
-// https://tools.ietf.org/html/rfc5869#appendix-A.
-static const HkdfTest kHkdfTests[] = {
- {
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c",
- "f0f1f2f3f4f5f6f7f8f9",
- "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
- },
- {
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c"
- "2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
- "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c"
- "8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
- "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc"
- "dddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
- "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e"
- "590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
- },
- {
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
- "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
- },
-};
-
-TEST(HkdfTest, Hkdf) {
- for (auto& test : kHkdfTests) {
- const string key = hex2str(test.key_hex);
- const string salt = hex2str(test.salt_hex);
- const string info = hex2str(test.info_hex);
- const string expected = hex2str(test.output_hex);
- size_t output_len = expected.size();
- uint8_t output[output_len];
- Rfc5869Sha256Kdf hkdf;
- ASSERT_TRUE(hkdf.Init(reinterpret_cast<const uint8_t*>(key.data()), key.size(),
- reinterpret_cast<const uint8_t*>(salt.data()), salt.size()));
- ASSERT_TRUE(hkdf.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
- output, output_len));
- EXPECT_EQ(0, memcmp(output, expected.data(), output_len));
- }
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/hmac_test.cpp b/unit_test/hmac_test.cpp
deleted file mode 100644
index 04f9356..0000000
--- a/unit_test/hmac_test.cpp
+++ b/dev/null
@@ -1,84 +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 "hmac.h"
-
-#include <gtest/gtest.h>
-#include <string.h>
-
-#include "android_keymaster_test_utils.h"
-
-using std::string;
-
-namespace keymaster {
-
-namespace test {
-
-struct HmacTest {
- const char* data;
- const char* key;
- uint8_t digest[32];
-};
-
-static const HmacTest kHmacTests[] = {
- {
- "Test Using Larger Than Block-Size Key - Hash Key First",
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- {
- 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5,
- 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f,
- 0x0e, 0xe3, 0x7f, 0x54,
- },
- },
- {
- "The test message for the MD2, MD5, and SHA-1 hashing algorithms.",
- "46697265666f7820616e64205468756e64657242697264206172652061776573"
- "6f6d652100",
- {
- 0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14,
- 0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d,
- 0x1d, 0x29, 0x40, 0x48,
- },
- },
-};
-
-TEST(HmacTest, SHA256) {
- for (size_t i = 0; i < 2; i++) {
- const HmacTest& test(kHmacTests[i]);
-
- HmacSha256 hmac;
- const string key = hex2str(test.key);
- Buffer key_buffer(key.data(), key.size());
- ASSERT_TRUE(hmac.Init(key_buffer));
-
- uint8_t digest_copy[sizeof(test.digest)];
- memcpy(digest_copy, test.digest, sizeof(test.digest));
- Buffer digest_buffer(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
-
- Buffer data_buffer(test.data, strlen(test.data));
- EXPECT_TRUE(hmac.Verify(data_buffer, digest_buffer));
-
- digest_copy[16] ^= 0x80;
- digest_buffer.Reinitialize(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
- EXPECT_FALSE(hmac.Verify(data_buffer, digest_buffer));
- }
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/kdf1_test.cpp b/unit_test/kdf1_test.cpp
deleted file mode 100644
index 9c8b0d5..0000000
--- a/unit_test/kdf1_test.cpp
+++ b/dev/null
@@ -1,60 +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.
- */
-
-#include "kdf1.h"
-#include <gtest/gtest.h>
-#include <string.h>
-
-#include "android_keymaster_test_utils.h"
-
-using std::string;
-
-namespace keymaster {
-
-namespace test {
-
-struct Kdf1Test {
- const char* key_hex;
- const char* expected_output_hex;
- keymaster_digest_t digest_type;
-};
-
-static const Kdf1Test kKdf1Tests[] = {
- {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
- "e113b64e135cf4e2292c75efe5288edfda4",
- "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d"
- "800c46954840ff32052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842"
- "dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04",
- KM_DIGEST_SHA1}};
-
-TEST(Kdf1Test, Kdf1) {
- for (auto& test : kKdf1Tests) {
- const string key = hex2str(test.key_hex);
- const string expected_output = hex2str(test.expected_output_hex);
- size_t output_len = expected_output.size();
- uint8_t output[output_len];
-
- Kdf1 kdf1;
- ASSERT_TRUE(
- kdf1.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
- ASSERT_TRUE(kdf1.GenerateKey(nullptr, 0, output, output_len));
- EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
- }
-}
-
-} // namespace test
-
-} // namespace keymaster
diff --git a/unit_test/kdf2_test.cpp b/unit_test/kdf2_test.cpp
deleted file mode 100644
index 29ff40a..0000000
--- a/unit_test/kdf2_test.cpp
+++ b/dev/null
@@ -1,86 +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.
- */
-
-#include "kdf2.h"
-#include <gtest/gtest.h>
-#include <string.h>
-
-#include "android_keymaster_test_utils.h"
-
-using std::string;
-
-namespace keymaster {
-
-namespace test {
-
-struct Kdf2Test {
- const char* key_hex;
- const char* info_hex;
- const char* expected_output_hex;
- keymaster_digest_t digest_type;
-};
-
-static const Kdf2Test kKdf2Tests[] = {
- {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
- "e113b64e135cf4e2292c75efe5288edfda4",
- "",
- "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac179f819a3d18412e9eb45668f"
- "2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a5"
- "9cdc24875a60b4aacb1319fa11c3365a8b79a44669f26fba933d012db213d7e3b16349",
- KM_DIGEST_SHA_2_256},
- {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
- "e113b64e135cf4e2292c75efe5288edfda4",
- "",
- "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263"
- "cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9a"
- "b3fb889b2d7767d3837eea4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807",
- KM_DIGEST_SHA1},
- {"CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A", "", "744AB703F5BC082E59185F6D049D2D367DB245C2",
- KM_DIGEST_SHA1},
- {"0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881", "",
- "03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA73"
- "2DBF386",
- KM_DIGEST_SHA1},
- {"5E10B967A95606853E528F04262AD18A4767C761163971391E17CB05A21668D4CE2B9F151617408042CE091958382"
- "3FD346D1751FBE2341AF2EE0461B62F100FFAD4F723F70C18B38238ED183E9398C8CA517EE0CBBEFFF9C59471FE27"
- "8093924089480DBC5A38E9A1A97D23038106847D0D22ECF85F49A861821199BAFCB0D74E6ACFFD7D142765EBF4C71"
- "2414FE4B6AB957F4CB466B46601289BB82060428272842EE28F113CD11F39431CBFFD823254CE472E2105E49B3D7F"
- "113B825076E6264585807BC46454665F27C5E4E1A4BD03470486322981FDC894CCA1E2930987C92C15A38BC42EB38"
- "810E867C4432F07259EC00CDBBB0FB99E1727C706DA58DD",
- "484D4143204B6579", "BC98EB018CB00EE26D1F97A15AE166912A7AC4C5", KM_DIGEST_SHA1},
-
-};
-
-TEST(Kdf2Test, Kdf2) {
- for (auto& test : kKdf2Tests) {
- const string key = hex2str(test.key_hex);
- const string info = hex2str(test.info_hex);
- const string expected_output = hex2str(test.expected_output_hex);
- size_t output_len = expected_output.size();
- uint8_t output[output_len];
-
- Kdf2 kdf2;
- ASSERT_TRUE(
- kdf2.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
- ASSERT_TRUE(kdf2.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
- output, output_len));
- EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
- }
-}
-
-} // namespace test
-
-} // namespace keymaster
diff --git a/unit_test/kdf_test.cpp b/unit_test/kdf_test.cpp
deleted file mode 100644
index f6f4a93..0000000
--- a/unit_test/kdf_test.cpp
+++ b/dev/null
@@ -1,46 +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.
- */
-
-#include "kdf.h"
-#include <gtest/gtest.h>
-
-namespace keymaster {
-
-namespace test {
-
-class ForTestAbstractKdf : public Kdf {
- bool GenerateKey(const uint8_t* /* info */, size_t /* info_len */, uint8_t* /* output */,
- size_t /* output_len */) {
- return true;
- }
-};
-
-TEST(KdfTest, Kdf) {
- ForTestAbstractKdf kdf;
- uint8_t key[128];
- uint8_t salt[128];
- ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, salt, 128));
- ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA_2_256, key, 128, salt, 128));
- ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, nullptr, 0));
- ASSERT_FALSE(kdf.Init(KM_DIGEST_MD5, key, 128, salt, 128));
- ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 0, salt, 128));
- ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 128, salt, 128));
- ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, key, 0, salt, 128));
-}
-
-} // namespace test
-
-} // namespace keymaster
diff --git a/unit_test/key_blob_test.cpp b/unit_test/key_blob_test.cpp
deleted file mode 100644
index 1e590f0..0000000
--- a/unit_test/key_blob_test.cpp
+++ b/dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2014 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 <algorithm>
-
-#include <gtest/gtest.h>
-
-#include <openssl/engine.h>
-#include <openssl/rand.h>
-
-#include <keymaster/authorization_set.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_tags.h>
-
-#include "android_keymaster_test_utils.h"
-#include "auth_encrypted_key_blob.h"
-#include "integrity_assured_key_blob.h"
-#include "ocb_utils.h"
-
-namespace keymaster {
-
-namespace test {
-
-const uint8_t master_key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-const uint8_t key_data[5] = {21, 22, 23, 24, 25};
-
-class KeyBlobTest : public testing::Test {
- protected:
- KeyBlobTest()
- : master_key_(master_key_data, array_length(master_key_data)),
- key_material_(key_data, array_length(key_data)) {
- hw_enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
- hw_enforced_.push_back(TAG_KEY_SIZE, 256);
- hw_enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
- hw_enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
- hw_enforced_.push_back(TAG_ALL_USERS);
- hw_enforced_.push_back(TAG_NO_AUTH_REQUIRED);
- hw_enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
-
- sw_enforced_.push_back(TAG_ACTIVE_DATETIME, 10);
- sw_enforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
- sw_enforced_.push_back(TAG_CREATION_DATETIME, 10);
-
- hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
- hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
-
- nonce_.reserve(OCB_NONCE_LENGTH);
- EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
- nonce_.advance_write(OCB_NONCE_LENGTH);
-
- tag_.reserve(OCB_TAG_LENGTH);
- }
-
- keymaster_error_t Encrypt() {
- return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_,
- nonce_, &ciphertext_, &tag_);
- }
-
- keymaster_error_t Decrypt() {
- return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_,
- tag_, &decrypted_plaintext_);
- }
-
- keymaster_error_t Serialize() {
- return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_,
- &serialized_blob_);
- }
-
- keymaster_error_t Deserialize() {
- return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_,
- &sw_enforced_, &nonce_, &tag_);
- }
-
- AuthorizationSet hw_enforced_;
- AuthorizationSet sw_enforced_;
- AuthorizationSet hidden_;
- Buffer nonce_, tag_;
-
- KeymasterKeyBlob master_key_;
- KeymasterKeyBlob key_material_;
- KeymasterKeyBlob ciphertext_;
- KeymasterKeyBlob decrypted_plaintext_;
- KeymasterKeyBlob serialized_blob_;
-};
-
-TEST_F(KeyBlobTest, EncryptDecrypt) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // key_data shouldn't be anywhere in the blob, ciphertext should.
- EXPECT_EQ(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
- key_material_.begin(), key_material_.end()));
- EXPECT_NE(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
- ciphertext_.begin(), ciphertext_.end()));
-
- ciphertext_.Clear();
- nonce_.Clear();
- tag_.Clear();
- AuthorizationSet hw2;
- AuthorizationSet sw2;
-
- ASSERT_EQ(KM_ERROR_OK, DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw2, &sw2,
- &nonce_, &tag_));
- KeymasterKeyBlob plaintext;
- OcbDecryptKey(hw2, sw2, hidden_, master_key_, ciphertext_, nonce_, tag_, &plaintext);
-
- EXPECT_EQ(hw_enforced_, hw2);
- EXPECT_EQ(sw_enforced_, sw2);
-
- ASSERT_EQ(key_material_.key_material_size, plaintext.key_material_size);
- EXPECT_EQ(0, memcmp(plaintext.begin(), key_material_.begin(), plaintext.key_material_size));
-}
-
-TEST_F(KeyBlobTest, WrongKeyLength) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Modify the key length, shouldn't be able to parse.
- serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++;
-
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize());
-}
-
-TEST_F(KeyBlobTest, WrongNonce) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Find the nonce, then modify it.
- auto nonce_ptr =
- std::search(serialized_blob_.begin(), serialized_blob_.end(), nonce_.begin(), nonce_.end());
- ASSERT_NE(nonce_ptr, serialized_blob_.end());
- EXPECT_EQ(serialized_blob_.end(),
- std::search(nonce_ptr + 1, serialized_blob_.end(), nonce_.begin(), nonce_.end()));
- (*const_cast<uint8_t*>(nonce_ptr))++;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
-}
-
-TEST_F(KeyBlobTest, WrongTag) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Find the tag, them modify it.
- auto tag_ptr =
- std::search(serialized_blob_.begin(), serialized_blob_.end(), tag_.begin(), tag_.end());
- ASSERT_NE(tag_ptr, serialized_blob_.end());
- EXPECT_EQ(serialized_blob_.end(),
- std::search(tag_ptr + 1, serialized_blob_.end(), tag_.begin(), tag_.end()));
- (*const_cast<uint8_t*>(tag_ptr))++;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
-}
-
-TEST_F(KeyBlobTest, WrongCiphertext) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Find the ciphertext, them modify it.
- auto ciphertext_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
- ciphertext_.begin(), ciphertext_.end());
- ASSERT_NE(ciphertext_ptr, serialized_blob_.end());
- EXPECT_EQ(serialized_blob_.end(), std::search(ciphertext_ptr + 1, serialized_blob_.end(),
- ciphertext_.begin(), ciphertext_.end()));
- (*const_cast<uint8_t*>(ciphertext_ptr))++;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
-}
-
-TEST_F(KeyBlobTest, WrongMasterKey) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- KeymasterKeyBlob wrong_master(wrong_master_data, array_length(wrong_master_data));
-
- // Decrypting with wrong master key should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, wrong_master, ciphertext_, nonce_,
- tag_, &decrypted_plaintext_));
-}
-
-TEST_F(KeyBlobTest, WrongHwEnforced) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Find enforced serialization data and modify it.
- size_t hw_enforced_size = hw_enforced_.SerializedSize();
- UniquePtr<uint8_t[]> hw_enforced_data(new uint8_t[hw_enforced_size]);
- hw_enforced_.Serialize(hw_enforced_data.get(), hw_enforced_data.get() + hw_enforced_size);
-
- auto hw_enforced_ptr =
- std::search(serialized_blob_.begin(), serialized_blob_.end(), hw_enforced_data.get(),
- hw_enforced_data.get() + hw_enforced_size);
- ASSERT_NE(serialized_blob_.end(), hw_enforced_ptr);
- EXPECT_EQ(serialized_blob_.end(),
- std::search(hw_enforced_ptr + 1, serialized_blob_.end(), hw_enforced_data.get(),
- hw_enforced_data.get() + hw_enforced_size));
- (*(const_cast<uint8_t*>(hw_enforced_ptr) + hw_enforced_size - 1))++;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
-}
-
-TEST_F(KeyBlobTest, WrongSwEnforced) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- // Find enforced serialization data and modify it.
- size_t sw_enforced_size = sw_enforced_.SerializedSize();
- UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]);
- sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size);
-
- auto sw_enforced_ptr =
- std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(),
- sw_enforced_data.get() + sw_enforced_size);
- ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr);
- EXPECT_EQ(serialized_blob_.end(),
- std::search(sw_enforced_ptr + 1, serialized_blob_.end(), sw_enforced_data.get(),
- sw_enforced_data.get() + sw_enforced_size));
- (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
-}
-
-TEST_F(KeyBlobTest, EmptyHidden) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- AuthorizationSet wrong_hidden;
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
- nonce_, tag_, &decrypted_plaintext_));
-}
-
-TEST_F(KeyBlobTest, WrongRootOfTrust) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- AuthorizationSet wrong_hidden;
- wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
- wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
- nonce_, tag_, &decrypted_plaintext_));
-}
-
-TEST_F(KeyBlobTest, WrongAppId) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
-
- AuthorizationSet wrong_hidden;
- wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
- wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7);
-
- // Deserialization shouldn't be affected, but decryption should fail.
- ASSERT_EQ(KM_ERROR_OK, Deserialize());
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
- nonce_, tag_, &decrypted_plaintext_));
-}
-
-// This test is especially useful when compiled for 32-bit mode and run under valgrind.
-TEST_F(KeyBlobTest, FuzzTest) {
- time_t now = time(NULL);
- std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
- srand(now);
-
- // Fill large buffer with random bytes.
- const int kBufSize = 10000;
- UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
- for (size_t i = 0; i < kBufSize; ++i)
- buf[i] = static_cast<uint8_t>(rand());
-
- // Try to deserialize every offset with multiple methods.
- size_t deserialize_auth_encrypted_success = 0;
- for (size_t i = 0; i < kBufSize; ++i) {
- keymaster_key_blob_t blob = {buf.get() + i, kBufSize - i};
- KeymasterKeyBlob key_blob(blob);
-
- // Integrity-assured blob.
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
- &sw_enforced_));
-
- // Auth-encrypted OCB blob.
- keymaster_error_t error = DeserializeAuthEncryptedBlob(
- key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, &nonce_, &tag_);
- if (error == KM_ERROR_OK) {
- // It's possible to deserialize successfully. Decryption should always fail.
- ++deserialize_auth_encrypted_success;
- error = OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_,
- nonce_, tag_, &decrypted_plaintext_);
- }
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error)
- << "Somehow sucessfully parsed a blob with seed " << now << " at offset " << i;
- }
-}
-
-TEST_F(KeyBlobTest, UnderflowTest) {
- uint8_t buf[0];
- keymaster_key_blob_t blob = {buf, 0};
- KeymasterKeyBlob key_blob(blob);
- EXPECT_NE(nullptr, key_blob.key_material);
- EXPECT_EQ(0U, key_blob.key_material_size);
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
- &sw_enforced_));
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
- &nonce_, &tag_));
-}
-
-TEST_F(KeyBlobTest, DupBufferToolarge) {
- uint8_t buf[0];
- keymaster_key_blob_t blob = {buf, 0};
- blob.key_material_size = 16 * 1024 * 1024 + 1;
- KeymasterKeyBlob key_blob(blob);
- EXPECT_EQ(nullptr, key_blob.key_material);
- EXPECT_EQ(0U, key_blob.key_material_size);
-
- ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
- &sw_enforced_));
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
- &nonce_, &tag_));
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/keymaster0_engine.h b/unit_test/keymaster0_engine.h
deleted file mode 100644
index aedd85c..0000000
--- a/unit_test/keymaster0_engine.h
+++ b/dev/null
@@ -1,103 +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 SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
-#define SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
-
-#include <memory>
-
-#include <openssl/ec.h>
-#include <openssl/engine.h>
-#include <openssl/ex_data.h>
-#include <openssl/rsa.h>
-
-#include <hardware/keymaster0.h>
-#include <hardware/keymaster_defs.h>
-
-namespace keymaster {
-
-struct KeymasterKeyBlob;
-
-/* Keymaster0Engine is a BoringSSL ENGINE that implements RSA & EC by forwarding the requested
- * operations to a keymaster0 module. */
-class Keymaster0Engine {
- public:
- /**
- * Create a Keymaster0Engine, wrapping the provided keymaster0_device. The engine takes
- * ownership of the device, and will close it during destruction.
- */
- explicit Keymaster0Engine(const keymaster0_device_t* keymaster0_device);
- ~Keymaster0Engine();
-
- bool supports_ec() const { return supports_ec_; }
-
- bool GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus,
- KeymasterKeyBlob* key_material) const;
- bool GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const;
-
- bool ImportKey(keymaster_key_format_t key_format, const KeymasterKeyBlob& to_import,
- KeymasterKeyBlob* imported_key_material) const;
- bool DeleteKey(const KeymasterKeyBlob& blob) const;
- bool DeleteAllKeys() const;
-
- RSA* BlobToRsaKey(const KeymasterKeyBlob& blob) const;
- EC_KEY* BlobToEcKey(const KeymasterKeyBlob& blob) const;
-
- const keymaster_key_blob_t* RsaKeyToBlob(const RSA* rsa) const;
- const keymaster_key_blob_t* EcKeyToBlob(const EC_KEY* rsa) const;
-
- const keymaster0_device_t* device() { return keymaster0_device_; }
-
- EVP_PKEY* GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const;
-
- private:
- Keymaster0Engine(const Keymaster0Engine&); // Uncopyable
- void operator=(const Keymaster0Engine&); // Unassignable
-
- static int keyblob_dup(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d, int index,
- long argl, void* argp);
- static void keyblob_free(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
- void* argp);
- static int rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len);
- static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
- unsigned int* sig_len, EC_KEY* ec_key);
-
- struct Malloc_Delete {
- void operator()(void* p) { free(p); }
- };
-
- bool Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& key_blob,
- const uint8_t* data, const size_t data_length,
- std::unique_ptr<uint8_t[], Malloc_Delete>* signature,
- size_t* signature_length) const;
-
- int RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) const;
- int EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig, unsigned int* sig_len,
- EC_KEY* ec_key) const;
-
- const keymaster0_device_t* keymaster0_device_;
- ENGINE* const engine_;
- int rsa_index_, ec_key_index_;
- bool supports_ec_;
- RSA_METHOD rsa_method_;
- ECDSA_METHOD ecdsa_method_;
-
- static Keymaster0Engine* instance_;
-};
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
diff --git a/unit_test/keymaster1_engine.h b/unit_test/keymaster1_engine.h
deleted file mode 100644
index 9e2f13e..0000000
--- a/unit_test/keymaster1_engine.h
+++ b/dev/null
@@ -1,123 +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 SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
-#define SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
-
-#include <memory>
-
-#include <openssl/ec.h>
-#include <openssl/engine.h>
-#include <openssl/ex_data.h>
-#include <openssl/rsa.h>
-
-#include <hardware/keymaster1.h>
-#include <hardware/keymaster_defs.h>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-
-#include "openssl_utils.h"
-
-namespace keymaster {
-
-class Keymaster1Engine {
- public:
- /**
- * Create a Keymaster1Engine, wrapping the provided keymaster1_device. The engine takes
- * ownership of the device, and will close it during destruction.
- */
- explicit Keymaster1Engine(const keymaster1_device_t* keymaster1_device);
- ~Keymaster1Engine();
-
- keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
- KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
- AuthorizationSet* sw_enforced) const;
-
- keymaster_error_t ImportKey(const AuthorizationSet& key_description,
- keymaster_key_format_t input_key_material_format,
- const KeymasterKeyBlob& input_key_material,
- KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
- AuthorizationSet* sw_enforced) const;
- keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const;
- keymaster_error_t DeleteAllKeys() const;
-
- struct KeyData {
- KeyData(const KeymasterKeyBlob& blob, const AuthorizationSet& params)
- : op_handle(0), begin_params(params), key_material(blob), error(KM_ERROR_OK),
- expected_openssl_padding(-1) {}
-
- keymaster_operation_handle_t op_handle;
- AuthorizationSet begin_params;
- AuthorizationSet finish_params;
- KeymasterKeyBlob key_material;
- keymaster_error_t error;
- int expected_openssl_padding;
- };
-
- RSA* BuildRsaKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
- keymaster_error_t* error) const;
- EC_KEY* BuildEcKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
- keymaster_error_t* error) const;
-
- KeyData* GetData(EVP_PKEY* key) const;
- KeyData* GetData(const RSA* rsa) const;
- KeyData* GetData(const EC_KEY* rsa) const;
-
- const keymaster1_device_t* device() const { return keymaster1_device_; }
-
- EVP_PKEY* GetKeymaster1PublicKey(const KeymasterKeyBlob& blob,
- const AuthorizationSet& additional_params,
- keymaster_error_t* error) const;
-
- private:
- Keymaster1Engine(const Keymaster1Engine&); // Uncopyable
- void operator=(const Keymaster1Engine&); // Unassignable
-
- RSA_METHOD BuildRsaMethod();
- ECDSA_METHOD BuildEcdsaMethod();
- void ConfigureEngineForRsa();
- void ConfigureEngineForEcdsa();
-
- keymaster_error_t Keymaster1Finish(const KeyData* key_data, const keymaster_blob_t& input,
- keymaster_blob_t* output);
-
- static int duplicate_key_data(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d,
- int index, long argl, void* argp);
- static void free_key_data(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
- void* argp);
-
- static int rsa_sign_raw(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
- const uint8_t* in, size_t in_len, int padding);
- static int rsa_decrypt(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
- const uint8_t* in, size_t in_len, int padding);
- static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
- unsigned int* sig_len, EC_KEY* ec_key);
-
- const keymaster1_device_t* const keymaster1_device_;
- const std::unique_ptr<ENGINE, ENGINE_Delete> engine_;
- const int rsa_index_;
- const int ec_key_index_;
-
- const RSA_METHOD rsa_method_;
- const ECDSA_METHOD ecdsa_method_;
-
- static Keymaster1Engine* instance_;
-};
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
diff --git a/unit_test/keymaster_configuration_test.cpp b/unit_test/keymaster_configuration_test.cpp
deleted file mode 100644
index 81e9598..0000000
--- a/unit_test/keymaster_configuration_test.cpp
+++ b/dev/null
@@ -1,68 +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.
- */
-
-#include <gtest/gtest.h>
-
-#include <keymaster/keymaster_configuration.h>
-
-#ifdef HOST_BUILD
-extern "C" {
-int __android_log_print(int prio, const char* tag, const char* fmt);
-int __android_log_print(int prio, const char* tag, const char* fmt) {
- (void)prio, (void)tag, (void)fmt;
- std::cout << fmt << std::endl;
- return 0;
-}
-} // extern "C"
-#endif // HOST_BUILD
-
-namespace keymaster {
-namespace test {
-
-TEST(VersionParsingTest, Full) {
- EXPECT_EQ(612334U, GetOsVersion("61.23.34"));
- EXPECT_EQ(680000U, GetOsVersion("681.23.24"));
- EXPECT_EQ(682300U, GetOsVersion("68.231.24"));
- EXPECT_EQ(682324U, GetOsVersion("68.23.241"));
- EXPECT_EQ(60102U, GetOsVersion("6.1.2-extrajunk"));
- EXPECT_EQ(0U, GetOsVersion("extra6.1.2"));
-}
-
-TEST(VersionParsingTest, FullWithExtraChars) {}
-
-TEST(VersionParsingTest, MajorOnly) {
- EXPECT_EQ(60000U, GetOsVersion("6"));
- EXPECT_EQ(680000U, GetOsVersion("68"));
- EXPECT_EQ(680000U, GetOsVersion("681"));
- EXPECT_EQ(60000U, GetOsVersion("6.junk"));
-}
-
-TEST(VersionParsingTest, MajorMinorOnly) {
- EXPECT_EQ(60100U, GetOsVersion("6.1"));
- EXPECT_EQ(60100U, GetOsVersion("6.1junk"));
-}
-
-TEST(PatchLevelParsingTest, Full) {
- EXPECT_EQ(201603U, GetOsPatchlevel("2016-03-23"));
- EXPECT_EQ(0U, GetOsPatchlevel("2016-13-23"));
- EXPECT_EQ(0U, GetOsPatchlevel("2016-03"));
- EXPECT_EQ(0U, GetOsPatchlevel("2016-3-23"));
- EXPECT_EQ(0U, GetOsPatchlevel("2016-03-23r"));
- EXPECT_EQ(0U, GetOsPatchlevel("r2016-03-23"));
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/keymaster_enforcement_test.cpp b/unit_test/keymaster_enforcement_test.cpp
deleted file mode 100644
index 3874744..0000000
--- a/unit_test/keymaster_enforcement_test.cpp
+++ b/dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright (C) 2014 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 <errno.h>
-#include <stdio.h>
-#include <time.h>
-
-#include <keymaster/android_keymaster.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/keymaster_enforcement.h>
-
-#include "android_keymaster_test_utils.h"
-
-namespace keymaster {
-namespace test {
-
-class TestKeymasterEnforcement : public KeymasterEnforcement {
- public:
- TestKeymasterEnforcement()
- : KeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {}
-
- keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
- const AuthorizationSet& auth_set) {
- AuthorizationSet empty_set;
- return KeymasterEnforcement::AuthorizeOperation(
- purpose, keyid, auth_set, empty_set, 0 /* op_handle */, true /* is_begin_operation */);
- }
- using KeymasterEnforcement::AuthorizeOperation;
-
- uint32_t get_current_time() const override { return current_time_; }
- bool activation_date_valid(uint64_t activation_date) const override {
- // Convert java date to time_t, non-portably.
- time_t activation_time = activation_date / 1000;
- return difftime(time(NULL), activation_time) >= 0;
- }
- bool expiration_date_passed(uint64_t expiration_date) const override {
- // Convert jave date to time_t, non-portably.
- time_t expiration_time = expiration_date / 1000;
- return difftime(time(NULL), expiration_time) > 0;
- }
- bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const {
- return current_time_ > ntoh(token.timestamp) + timeout;
- }
- bool ValidateTokenSignature(const hw_auth_token_t&) const override {
- return report_token_valid_;
- }
-
- void tick(unsigned seconds = 1) { current_time_ += seconds; }
- uint32_t current_time() { return current_time_; }
- void set_report_token_valid(bool report_token_valid) {
- report_token_valid_ = report_token_valid;
- }
-
- private:
- uint32_t current_time_;
- bool report_token_valid_;
-};
-
-class KeymasterBaseTest : public ::testing::Test {
- protected:
- KeymasterBaseTest() {
- past_time = 0;
-
- time_t t = time(NULL);
- future_tm = localtime(&t);
- future_tm->tm_year += 1;
- future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000;
- sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
- }
- virtual ~KeymasterBaseTest() {}
-
- TestKeymasterEnforcement kmen;
-
- tm past_tm;
- tm* future_tm;
- uint64_t past_time;
- uint64_t future_time;
- static const km_id_t key_id = 0xa;
- static const uid_t uid = 0xf;
- keymaster_key_param_t sign_param;
-};
-
-TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) {
- keymaster_key_param_t params[] = {
- sign_param,
- };
- AuthorizationSet single_auth_set(params, array_length(params));
-
- keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidActiveTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-
- // Pubkey ops allowed.
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestValidActiveTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_valid_time = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer_valid_time);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-
- // Pubkey ops allowed.
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
-}
-
-TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_valid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidPubkeyUsageExpireTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
- // Pubkey ops allowed.
- ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_invalid_origination =
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
-}
-
-TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer_valid_usage =
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
- ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage);
-}
-
-TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
-
- ASSERT_EQ(KM_ERROR_OK, kmer1);
- ASSERT_EQ(KM_ERROR_OK, kmer2);
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidMaxOps) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_MAX_USES_PER_BOOT, 4),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- // Pubkey ops allowed.
- ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_MAX_USES_PER_BOOT, 2),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, auth_set));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, auth_set));
-
- // Key 4 should fail, because table is full.
- EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
-
- // Key 1 still works, because it's already in the table and hasn't reached max.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
-
- // Key 1 no longer works, because it's reached max.
- EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
-
- // Key 4 should fail, because table is (still and forever) full.
- EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
-
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
- keymaster_error_t kmer3 = kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
-
- ASSERT_EQ(KM_ERROR_OK, kmer1);
- kmen.tick(2);
- ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2);
-
- // Allowed because it's a pubkey op.
- ASSERT_EQ(KM_ERROR_OK, kmer3);
-}
-
-TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
- kmen.tick();
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- kmen.tick();
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
- Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4),
- Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 1 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 1 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- // Key 2 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 1 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- // Key 2 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
- // Key 3 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
- // Key 4 fails because the table is full
- EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 4 succeeds because key 1 expired.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
-
- // Key 1 fails because the table is full... and key 1 is no longer in it.
- EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- // Key 2 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
- // Key 3 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 1 succeeds because key 2 expired
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- // Key 2 fails because the table is full... and key 2 is no longer in it.
- EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
- // Key 3 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
- // Key 4 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
-
- kmen.tick(4);
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestPubkeyOptTimeoutTableOverflow) {
- keymaster_key_param_t params[] = {
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
- Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
- };
-
- AuthorizationSet auth_set(params, array_length(params));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
-
- kmen.tick();
-
- // Key 1 fails because it's too soon
- EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
- // Too soo, but pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidPurpose) {
- keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1);
- keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4);
-
- AuthorizationSet auth_set(
- AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
-
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
- kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set));
- EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
- kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) {
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
- kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
- kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) {
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-
- // This one is allowed because it's a pubkey op.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
- EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
- kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) {
- AuthorizationSet no_caller_nonce(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES));
- AuthorizationSet caller_nonce(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC)
- .Authorization(TAG_CALLER_NONCE));
- AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3));
-
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, caller_nonce, begin_params,
- 0 /* challenge */, true /* is_begin_operation */));
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, caller_nonce, begin_params,
- 0 /* challenge */, true /* is_begin_operation */));
- EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
- kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, no_caller_nonce, begin_params,
- 0 /* challenge */, true /* is_begin_operation */));
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, no_caller_nonce, begin_params,
- 0 /* challenge */, true /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestBootloaderOnly) {
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_BOOTLOADER_ONLY));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestInvalidTag) {
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_INVALID)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- kmen.set_report_token_valid(false);
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- token.challenge + 1 /* doesn't match token */,
- false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(
- AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(
- AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
- // Pubkey op allowed.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 10;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_USER_SECURE_ID, token.authenticator_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = 0;
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
-
- // During begin we can skip the auth token
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- token.challenge, true /* is_begin_operation */));
- // Afterwards we must have authentication
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
- // Pubkey ops allowed
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-
- auth_set.Reinitialize(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
- .build());
-
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) {
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_USER_SECURE_ID, 1)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
-}
-
-TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = hton(kmen.current_time());
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_AUTH_TIMEOUT, 1)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- 0 /* irrelevant */, false /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_AUTH_TIMEOUT, 1)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
- op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
-
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- 0 /* irrelevant */, false /* is_begin_operation */));
-
- kmen.tick(1);
-
- // token still good
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- 0 /* irrelevant */, false /* is_begin_operation */));
-
- kmen.tick(1);
-
- // token expired, not allowed during begin.
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- 0 /* irrelevant */, true /* is_begin_operation */));
-
- // token expired, afterwards it's okay.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
- 0 /* irrelevant */, false /* is_begin_operation */));
-
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- 0 /* irrelevant */, true /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) {
- hw_auth_token_t token;
- memset(&token, 0, sizeof(token));
- token.version = HW_AUTH_TOKEN_VERSION;
- token.challenge = 99;
- token.user_id = 9;
- token.authenticator_id = 0;
- token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
- token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
-
- AuthorizationSet auth_set(AuthorizationSetBuilder()
- .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
- .Authorization(TAG_USER_SECURE_ID, token.user_id)
- .Authorization(TAG_AUTH_TIMEOUT, 1)
- .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
- .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
-
- AuthorizationSet op_params;
-
- // Unlike auth-per-op, must have the auth token during begin.
- EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- true /* is_begin_operation */));
-
- // Later we don't check (though begin would fail, so there wouldn't be a later).
- EXPECT_EQ(KM_ERROR_OK,
- kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
- false /* is_begin_operation */));
-
- // Pubkey ops allowed.
- EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
- token.challenge, true /* is_begin_operation */));
-}
-
-TEST_F(KeymasterBaseTest, TestCreateKeyId) {
- keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6};
-
- km_id_t key_id = 0;
- EXPECT_TRUE(KeymasterEnforcement::CreateKeyId(blob, &key_id));
- EXPECT_NE(0U, key_id);
-}
-
-}; /* namespace test */
-}; /* namespace keymaster */
diff --git a/unit_test/keymaster_tags.cpp b/unit_test/keymaster_tags.cpp
deleted file mode 100644
index 238bc33..0000000
--- a/unit_test/keymaster_tags.cpp
+++ b/dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2014 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 <keymaster/keymaster_tags.h>
-
-namespace keymaster {
-
-#ifdef KEYMASTER_NAME_TAGS
-const char* StringifyTag(keymaster_tag_t tag) {
- switch (tag) {
- case KM_TAG_INVALID:
- return "KM_TAG_INVALID";
- case KM_TAG_PURPOSE:
- return "KM_TAG_PURPOSE";
- case KM_TAG_ALGORITHM:
- return "KM_TAG_ALGORITHM";
- case KM_TAG_KEY_SIZE:
- return "KM_TAG_KEY_SIZE";
- case KM_TAG_BLOCK_MODE:
- return "KM_TAG_BLOCK_MODE";
- case KM_TAG_DIGEST:
- return "KM_TAG_DIGEST";
- case KM_TAG_PADDING:
- return "KM_TAG_PADDING";
- case KM_TAG_CALLER_NONCE:
- return "KM_TAG_CALLER_NONCE";
- case KM_TAG_MIN_MAC_LENGTH:
- return "KM_TAG_MIN_MAC_LENGTH";
- case KM_TAG_RSA_PUBLIC_EXPONENT:
- return "KM_TAG_RSA_PUBLIC_EXPONENT";
- case KM_TAG_BLOB_USAGE_REQUIREMENTS:
- return "KM_TAG_BLOB_USAGE_REQUIREMENTS";
- case KM_TAG_BOOTLOADER_ONLY:
- return "KM_TAG_BOOTLOADER_ONLY";
- case KM_TAG_ACTIVE_DATETIME:
- return "KM_TAG_ACTIVE_DATETIME";
- case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
- return "KM_TAG_ORIGINATION_EXPIRE_DATETIME";
- case KM_TAG_USAGE_EXPIRE_DATETIME:
- return "KM_TAG_USAGE_EXPIRE_DATETIME";
- case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
- return "KM_TAG_MIN_SECONDS_BETWEEN_OPS";
- case KM_TAG_MAX_USES_PER_BOOT:
- return "KM_TAG_MAX_USES_PER_BOOT";
- case KM_TAG_ALL_USERS:
- return "KM_TAG_ALL_USERS";
- case KM_TAG_USER_ID:
- return "KM_TAG_USER_ID";
- case KM_TAG_USER_SECURE_ID:
- return "KM_TAG_USER_SECURE_ID";
- case KM_TAG_NO_AUTH_REQUIRED:
- return "KM_TAG_NO_AUTH_REQUIRED";
- case KM_TAG_USER_AUTH_TYPE:
- return "KM_TAG_USER_AUTH_TYPE";
- case KM_TAG_AUTH_TIMEOUT:
- return "KM_TAG_AUTH_TIMEOUT";
- case KM_TAG_ALL_APPLICATIONS:
- return "KM_TAG_ALL_APPLICATIONS";
- case KM_TAG_APPLICATION_ID:
- return "KM_TAG_APPLICATION_ID";
- case KM_TAG_APPLICATION_DATA:
- return "KM_TAG_APPLICATION_DATA";
- case KM_TAG_CREATION_DATETIME:
- return "KM_TAG_CREATION_DATETIME";
- case KM_TAG_ORIGIN:
- return "KM_TAG_ORIGIN";
- case KM_TAG_ROLLBACK_RESISTANT:
- return "KM_TAG_ROLLBACK_RESISTANT";
- case KM_TAG_ROOT_OF_TRUST:
- return "KM_TAG_ROOT_OF_TRUST";
- case KM_TAG_ASSOCIATED_DATA:
- return "KM_TAG_ASSOCIATED_DATA";
- case KM_TAG_NONCE:
- return "KM_TAG_NONCE";
- case KM_TAG_AUTH_TOKEN:
- return "KM_TAG_AUTH_TOKEN";
- case KM_TAG_MAC_LENGTH:
- return "KM_TAG_MAC_LENGTH";
- case KM_TAG_KDF:
- return "KM_TAG_KDF";
- case KM_TAG_EC_CURVE:
- return "KM_TAG_EC_CURVE";
- case KM_TAG_ECIES_SINGLE_HASH_MODE:
- return "KM_TAG_ECIES_SINGLE_HASH_MODE";
- case KM_TAG_OS_VERSION:
- return "KM_TAG_OS_VERSION";
- case KM_TAG_OS_PATCHLEVEL:
- return "KM_TAG_OS_PATCHLEVEL";
- case KM_TAG_EXPORTABLE:
- return "KM_TAG_EXPORTABLE";
- case KM_TAG_UNIQUE_ID:
- return "KM_TAG_UNIQUE_ID";
- case KM_TAG_INCLUDE_UNIQUE_ID:
- return "KM_TAG_INCLUDE_UNIQUE_ID";
- case KM_TAG_RESET_SINCE_ID_ROTATION:
- return "KM_TAG_RESET_SINCE_ID_ROTATION";
- case KM_TAG_ALLOW_WHILE_ON_BODY:
- return "KM_TAG_ALLOW_WHILE_ON_BODY";
- case KM_TAG_ATTESTATION_CHALLENGE:
- return "KM_TAG_ATTESTATION_CHALLENGE";
- }
- return "<Unknown>";
-}
-#endif // KEYMASTER_NAME_TAGS
-
-// DEFINE_KEYMASTER_TAG is used to create TypedTag instances for each non-enum keymaster tag.
-#define DEFINE_KEYMASTER_TAG(type, name) TypedTag<type, KM_##name> name
-
-DEFINE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH);
-DEFINE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID);
-DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME);
-DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME);
-DEFINE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
-DEFINE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA);
-DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
-DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
-DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
-DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
-
-// DEFINE_KEYMASTER_ENUM_TAG is used to create TypedEnumTag instances for each enum keymaster tag.
-
-#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) TypedEnumTag<type, KM_##name, enumtype> name
-
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS,
- keymaster_key_blob_usage_requirements_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t);
-DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t);
-
-} // namespace keymaster
diff --git a/unit_test/nist_curve_key_exchange_test.cpp b/unit_test/nist_curve_key_exchange_test.cpp
deleted file mode 100644
index 39ea38b..0000000
--- a/unit_test/nist_curve_key_exchange_test.cpp
+++ b/dev/null
@@ -1,219 +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.
- */
-
-#include "nist_curve_key_exchange.h"
-
-#include <gtest/gtest.h>
-#include <openssl/evp.h>
-
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-
-#include "android_keymaster_test_utils.h"
-
-using std::string;
-
-namespace keymaster {
-namespace test {
-
-StdoutLogger logger;
-
-static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
- KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
-
-/**
- * SharedKey just tests that the basic key exchange identity holds: that both
- * parties end up with the same key.
- */
-TEST(NistCurveKeyExchange, SharedKey) {
- for (auto& curve : kEcCurves) {
- AuthorizationSet kex_description(
- AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
- for (size_t j = 0; j < 5; j++) {
- NistCurveKeyExchange* alice_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
- NistCurveKeyExchange* bob_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
-
- ASSERT_TRUE(alice_keyex != nullptr);
- ASSERT_TRUE(bob_keyex != nullptr);
-
- Buffer alice_public_value;
- ASSERT_TRUE(alice_keyex->public_value(&alice_public_value));
- Buffer bob_public_value;
- ASSERT_TRUE(bob_keyex->public_value(&bob_public_value));
-
- Buffer alice_shared, bob_shared;
- ASSERT_TRUE(alice_keyex->CalculateSharedKey(bob_public_value, &alice_shared));
- ASSERT_TRUE(bob_keyex->CalculateSharedKey(alice_public_value, &bob_shared));
- EXPECT_EQ(alice_shared.available_read(), bob_shared.available_read());
- EXPECT_EQ(0, memcmp(alice_shared.peek_read(), bob_shared.peek_read(),
- alice_shared.available_read()));
- }
- }
-}
-
-/*
- * This test tries a key agreement with a false public key (i.e. with
- * a point not on the curve.)
- * The expected result of such a protocol should be that the
- * key agreement fails and returns an error.
-*/
-static const char* kInvalidPublicKeys[] = {
- "04" // uncompressed public key
- "deadbeef7f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
- "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
-};
-
-TEST(NistCurveKeyExchange, InvalidPublicKey) {
- for (auto& curve : kEcCurves) {
- AuthorizationSet kex_description(
- AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
- KeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
- ASSERT_TRUE(key_exchange != nullptr);
-
- string peer_public_key = hex2str(kInvalidPublicKeys[0]);
- Buffer computed_shared_secret;
- ASSERT_FALSE(key_exchange->CalculateSharedKey(
- reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
- &computed_shared_secret));
- }
-}
-
-/**
- * Test that key exchange fails when peer public key is the point at infinity.
- */
-TEST(NistCurveKeyExchange, TestInfinity) {
- for (auto& curve : kEcCurves) {
- /* Obtain the point at infinity */
- EC_GROUP* group = ec_get_group(curve);
- EC_POINT* point_at_infinity = EC_POINT_new(group);
- EC_POINT_set_to_infinity(group, point_at_infinity);
- EXPECT_EQ(1, EC_POINT_is_on_curve(group, point_at_infinity, nullptr));
- size_t field_len_in_bits;
- ec_get_group_size(group, &field_len_in_bits);
- size_t field_len = (field_len_in_bits + 7) / 8;
- size_t public_key_len = (field_len * 2) + 1;
- uint8_t* public_key = new uint8_t[public_key_len];
- public_key_len = EC_POINT_point2oct(group, point_at_infinity, POINT_CONVERSION_UNCOMPRESSED,
- public_key, public_key_len, nullptr /* ctx */);
-
- /* Perform the key exchange */
- AuthorizationSet kex_description(
- AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
- NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
- ASSERT_TRUE(key_exchange != nullptr);
- Buffer computed_shared_secret;
- /* It should fail */
- ASSERT_FALSE(key_exchange->CalculateSharedKey(reinterpret_cast<const uint8_t*>(public_key),
- public_key_len, &computed_shared_secret));
-
- /* Explicitly test that ECDH_compute_key fails when the public key is the point at infinity
- */
- UniquePtr<uint8_t[]> result(new uint8_t[field_len]);
- EXPECT_EQ(-1 /* error */, ECDH_compute_key(result.get(), field_len, point_at_infinity,
- key_exchange->private_key(), nullptr /* kdf */));
- }
-}
-
-/* Test vectors for P-256, downloaded from NIST. */
-struct NistCurveTest {
- const keymaster_ec_curve_t curve;
- const char* peer_public_key;
- const char* my_private_key;
- const char* shared_secret;
-};
-
-static const NistCurveTest kNistCurveTests[] = {
- {
- KM_EC_CURVE_P_256,
- "04" // uncompressed public key
- "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
- "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
- // https://tools.ietf.org/html/rfc5915
- "30770201010420" // DER-encodeded EC private key header
- "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" // private key
- "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
- "04"
- "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230"
- "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
- "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
- },
- {
- KM_EC_CURVE_P_256, "04"
- "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
- "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
- // https://tools.ietf.org/html/rfc5915
- "30770201010420" // DER-encodeded EC private key header
- "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5" // private key
- "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
- "04"
- "119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d0"
- "8f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
- "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
- },
- {
- KM_EC_CURVE_P_256, "04"
- "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
- "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
- // https://tools.ietf.org/html/rfc5915
- "30770201010420" // DER-encodeded EC private key header
- "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d" // private key
- "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
- "04"
- "24277c33f450462dcb3d4801d57b9ced05188f16c28eda873258048cd1607e0d"
- "c4789753e2b1f63b32ff014ec42cd6a69fac81dfe6d0d6fd4af372ae27c46f88",
- "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024",
- },
-};
-
-/**
- * Test that key exchange works with NIST test vectors.
- */
-TEST(NistCurveKeyExchange, NistTestVectors) {
- for (auto& test : kNistCurveTests) {
- string private_key = hex2str(test.my_private_key);
- string shared_secret = hex2str(test.shared_secret);
-
- const uint8_t* private_key_data = reinterpret_cast<const uint8_t*>(private_key.data());
- UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(
- d2i_ECPrivateKey(nullptr, &private_key_data, private_key.size()));
- ASSERT_TRUE(ec_key.get() && EC_KEY_check_key(ec_key.get()));
-
- keymaster_error_t error;
- NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(ec_key.release(), &error);
- EXPECT_EQ(KM_ERROR_OK, error);
- ASSERT_TRUE(key_exchange != nullptr);
-
- Buffer computed_shared_secret;
- string peer_public_key = hex2str(test.peer_public_key);
- ASSERT_TRUE(key_exchange->CalculateSharedKey(
- reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
- &computed_shared_secret));
- EXPECT_EQ(shared_secret.size(), computed_shared_secret.available_read());
- EXPECT_EQ(0, memcmp(shared_secret.data(), computed_shared_secret.peek_read(),
- shared_secret.size()));
-
- for (size_t i = 0; i < peer_public_key.size(); i++) {
- // randomly flip some bits in the peer public key to make it invalid
- peer_public_key[i] ^= 0xff;
- ASSERT_FALSE(key_exchange->CalculateSharedKey(
- reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
- &computed_shared_secret));
- }
- }
-}
-
-} // namespace test
-} // namespace keymaster
diff --git a/unit_test/openssl_utils.h b/unit_test/openssl_utils.h
deleted file mode 100644
index 9fa6ec1..0000000
--- a/unit_test/openssl_utils.h
+++ b/dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2014 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 SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
-#define SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
-
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/engine.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/x509.h>
-
-#include <UniquePtr.h>
-
-#include <hardware/keymaster_defs.h>
-
-namespace keymaster {
-
-struct KeymasterKeyBlob;
-
-class EvpMdCtxCleaner {
- public:
- explicit EvpMdCtxCleaner(EVP_MD_CTX* ctx) : ctx_(ctx) {}
- ~EvpMdCtxCleaner() { EVP_MD_CTX_cleanup(ctx_); }
-
- private:
- EVP_MD_CTX* ctx_;
-};
-
-template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
- void operator()(T* p) { FreeFunc(p); }
-};
-
-#define DEFINE_OPENSSL_OBJECT_POINTER(name) \
- typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
- typedef UniquePtr<name, name##_Delete> name##_Ptr;
-
-DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING)
-DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER)
-DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OBJECT)
-DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING)
-DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME)
-DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX)
-DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP)
-DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY)
-DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT)
-DEFINE_OPENSSL_OBJECT_POINTER(ENGINE)
-DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY)
-DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO)
-DEFINE_OPENSSL_OBJECT_POINTER(RSA)
-DEFINE_OPENSSL_OBJECT_POINTER(X509)
-DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION)
-DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME)
-
-typedef OpenSslObjectDeleter<BIGNUM, BN_free> BIGNUM_Delete;
-typedef UniquePtr<BIGNUM, BIGNUM_Delete> BIGNUM_Ptr;
-
-keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits);
-EC_GROUP* ec_get_group(keymaster_ec_curve_t curve);
-
-/**
- * Many OpenSSL APIs take ownership of an argument on success but don't free the argument on
- * failure. This means we need to tell our scoped pointers when we've transferred ownership, without
- * triggering a warning by not using the result of release().
- */
-template <typename T, typename Delete_T>
-inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) {
- T* val __attribute__((unused)) = p.release();
-}
-
-keymaster_error_t convert_pkcs8_blob_to_evp(const uint8_t* key_data, size_t key_length,
- keymaster_algorithm_t expected_algorithm,
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey);
-
-keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
- const KeymasterKeyBlob& key_material,
- keymaster_algorithm_t expected_algorithm,
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* evp_pkey);
-
-keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
-
-size_t ec_group_size_bits(EC_KEY* ec_key);
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
diff --git a/unit_test/sw_rsa_attest_root.key.pem b/unit_test/sw_rsa_attest_root.key.pem
deleted file mode 100644
index 387a852..0000000
--- a/unit_test/sw_rsa_attest_root.key.pem
+++ b/dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAsQ+wz
-fNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdLt0GA
-ZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwIDAQAB
-AoGAU8dxXchmqzVNbbvff7zgUa63YErk51Yem/EXzhkMaIXRkMO0edaCtZtnkRvg
-9OQ2qEiLWaCTlUoyU7H/HUn2lwTQsOXyZI7dHijVDRMIv1mmrHCrGW/JC8FXfPLS
-r3L3KoHXQVYL2mslbR8Rpogxq4WwnwK6XqSTH9mynFwQwEkCQQDMX3EZk3ricWVH
-ruXD0BpXOMMpZuLu4rg5+1L51WEJvItIMeSjLuNa+g3AI8AYTYYi/aSLk6XEv82L
-iXFGmJ2XAkEAy3M8k8Z0QzHae4olduqoHVWEarBtDE+fqFQBWgdm8fZhdHWrvlAc
-qwJIXMUVc+dWm/FAQarCjbqWqhCRdaYgnQJBAJ7z7GdUCVNtlrQ2F4ZAqPwFreTZ
-nM7njxmpm1Os3hhQiJPSGl3A7huoOGGkbJd6VEWKuRvF7jwkYZ2RfITH1mkCQAvh
-X9E1Toa5+4spRwTJsSV9X+0m/kcwwx7+QNH0CrPockptsKi9Xt8xk+4u6BDLmogi
-r2DmStQh6DhoHUZkfBUCQQCOgBkqH/15drpdR+BQH3VaP4/ALFfxR9E3G+lS+M5a
-IqJEk9kh8vjuGzTaAZyU5keUmpWNc1gI7OvDMaH4+8vQ
------END RSA PRIVATE KEY-----