author | Xindong 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) |
commit | 5f98c979d780115f85f8c815e57a620b73471bfc (patch) | |
tree | f5a1bed37f9244a934625bdae5c7d8246b0d7aab | |
parent | ee9f363f98df4f99de4efcec553f97ae654e474c (diff) | |
download | keymaster-5f98c979d780115f85f8c815e57a620b73471bfc.zip keymaster-5f98c979d780115f85f8c815e57a620b73471bfc.tar.gz keymaster-5f98c979d780115f85f8c815e57a620b73471bfc.tar.bz2 |
keymaster: sync to ref q
2e847b99eabc67bc7ba1fccb77d7aa3399eb7d75
Change-Id: I37fbba12c99ce802dd1f636d1b69922ab037875e
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 -®
ù¾˜?G5q„}#õ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(DD˜ëó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<ø7Cê +c@D +›ø1Œë Dø4<ø3Cê +ê +€ê¹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ê…LEê†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êULêÅ|- +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ê…NEê†<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êUNêÅ~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 Fo9Fÿ÷ÄýF ¹PFLFÿ÷åüëç hñ€E +ÙJD +Ùe"D +FE +¿#hOðÿ0h½8µFFÿ÷ +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*CC -êÚñ -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ôØrI
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ë
ih(¿ ñ -ü÷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ëaMih(¿ ñ -›šEëÛÐç ñÿ6Oð XF1Fÿ÷°øX»¹ñ -ú -üÂFLðñàOðOð -àF¸EßÛáçOêl2ª - -ë -³ÔOð -¨ú÷Úû F3°½èð-éðGFFF‘FFû÷ú¾BÐNEÑ(Fû÷FúF -ÐK# -à(F -Ðj+F:F G -ñ8 -Ðj - -¾”½è0@ÿ÷ò¾i±ÿ÷˜¾ÿ÷f¿ -Ñ@ò# -žZÑÐø€àñ -FFÿ÷–ÿ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ëih(¿ ñ -Ýø(àZF^ø0;:úóîÐ ñ ˜EáÑ®²B
Ð@òe -˜Oê‰Pø)0+ØàWø)0
™hþ÷Žÿ -àWø0 -ñÿ2 + ñ +ëGë†aÎih(¿ +ñ +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 +IH{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" +IH{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 Ñ,¹hhšBÑ0¼Ãç +ÐÄiÍi¬B Ñ,¹hhš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‡"am8åýD꾤©ÏÞK`K»öp¼¿¾Æ~›(ú'¡ê…0ïÔˆ9ÐÔÙå™Ûæø|¢eV¬ÄD")ô—ÿ*C§#”«9 “üÃY[e’ÌÑ]„…O~¨oàæ,þC£¡N‚~S÷»Ò×*5ò:½‘Ó†ë]/ÖSDæ¡ØÈûÓçæÍá!Ö7Ç
ÕôíZEéã©ø£ïüÙogŠL*‹mpµFF?+Ù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@’Äéš‚êš‚ê +pFF˜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*qjq ªq£hër*rjr ªrãhës*sjs ªs#iët*tjt -ª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*pjp -ª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(php -¨p*qjq -ªq5BëÑ p½<ñ@Tø?bhëqêp(php -¨p*qjq -ª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@ø$;ð)ùñ -KJµF{D›X3`@k±Dð{þñ -KJµF{D›X3`@k±DðCþñ -KJµ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
HxDpGHxDpGHxDpGHxDpGHxDpG -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 -LKµ"|D‹!{D F -e -þб(Bðôýh™[i˜GF¨¹à®)F0F4Bð•ý–è -(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ËabKbpGKÁ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 +ðßúóçô¡ +JIzDRXñFBøÂ` +KJµF{D›X3`Àh±Lð¯ûñ< +JzDòBÙç JzDõzrÔçJzDõ~rÏç +KJµF{D›X3@ø8;ðÿÿñ$ +JµF{D0šX2@ø,J›X3@ø<Lðæø F½ +KJµ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 +MK}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 +± +KLµŒ!{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ð +Øßèð "$JxxCê#Š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 -NM|DK~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 -NM|DK~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 -NM|DK~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÷÷ñø¤à
ñDOð -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 ph3`pGhpØpZp - šph3`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ð´û(D5F©ç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ù›ç +)OFFD!ØÃ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ÃajbKjCb +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Ðù +Ù¥ñ Û²+ +Ø&úóð¿"ð€¿$ßç"øç äç âçûÿ§hhhhÀ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¿FF~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
DDIcCH¿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µFFF7ð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›"IKxDyD{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" -IKxDyD{D)ð¯ÿ)ðÁÿ{±hðuø hðrø -kh±2{BóÓ¹`l`à+h"Zsà ½èøƒ -àOðƒ&àOð‚&àOð&ñÿ9 -IKxDyD{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”" +IH{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› -FFÝ÷êþ -”Ý÷±ÿ„B¿ë -šð`ø ›D$ê -z - -FFø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ÃyqÈKqCh ‹qChËqÃzrC‰Krƒh ‹rƒhËrÃ{sÉKsÃh ‹sÃhËsÃ|tCŠKti -‹tiËtpG -”pÄX3 +Ôpðѽñ@ÃypÈKpCh -‹pChËpÃxqCˆ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¨ -FFØ÷þ -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ŠhiÑø -•%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µ©°FhFFÿ÷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ëFFÝé ’cë FÍé#b
k©FBêÅ"ÝéE_€OêBVAëGêÒ'KB
OêC[BêÁ"¸ëië KêÒ+¤OêBZEëÍé‰FF²ë -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 -“u3NFCê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ê„t8”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ëFFÝé²ëcë Íé#kb
OêCYBêÅ"€IêÒ)OêBXAë"F+FÝéE²ëcë Íé#KB
OêCYBêÁ"¤IêÒ)OêBXEëFFÝé²ëcë Íé#kb
OêCYBêÅ"€IêÒ)OêBXAë"F+FÝé -E²ëcë Íé#KB
OêCYBêÁ"¤IêÒ)OêBXEëFFÝé²ëcë Íé -#kb
OêCYBêÅ"€IêÒ)OêBXAë"F+FÝéE²ëcë Íé#KB
OêCYBêÁ"¤IêÒ)OêBXEëFF²ë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ËtpG8$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``à`ª‰`ºñ -FF ‘ÿ÷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ÿ÷§ý -FFð÷!þ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½ -FFÎ÷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+ïÑ + + + + + +LM|DdY”œ”
œ”œè +LM|DdY”œ”
œ”œè +L +M|DdY”œ”
œ”œè +LM|DdY”œ”
œ”œè +L +M|DdY”œ”
œ”œè +LM|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ÑyDz£õ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¿" +IH{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½ÿ(Ù.JF!(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ð1hJù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°" +IH{D3yDxDðç(Fõ÷èþ%f´çh +hhQhXhð÷Ì¿7µFM}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ÿô6KHFZø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& +MI{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 +*ÚÑ#°½èð— +F8FF&ÿ÷Éø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 +,ØÑ +,ÛÑKjiÍh + h§ëñ€gñ +*ÛÑ °½èð +,ØÑ +,ÛÑKjiÍh +*ÛÑ °½èð +*ØÑÑø$ÀÑø àÌiiNiiÑø€‘è"K°î[[` KšžB`JFaÄa¢ë ×U`¢ë£ëÁ`!b +*ÛѽèøƒÚÿÿþÿÿþÿÿ¬Š +*ØÑÑø +KhŠhÌhOië˜cŽiÍi(ð|HëSb#ð~C·î[ë’ni"ð|Bë^ljIjëœ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 "88Fðú;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@ò#1H*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 +`ü÷ÍúJKzDã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
FFiF -x±h -h
FðÐh -!¡÷§üC4Ð( Ð(Ð#hCðà#hCð#` -Fø@ø0# -ÐE4¿GFWFø0F«÷hû -FF«÷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$R2(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„K0L0„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¬€2tE3t~ 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|PV×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 NC¾¶Gç*b]¦Å3bV$²¼fCÑhÕ;i¦ž¸|Õ¯>!1뤘òj^|›E²ÕŒ²§W_/OÛR™|X_ò¥öQ†!/[j®ƒ4mXKïþ¿s]ÛÄ—*…ólFB³ÁW—P5±·Ç<…mlýΰɢwîÃk7ú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 +®
ù¾˜?G5q„}#õ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 í ñ ó -#)-?GQW]eo{‰“™›·¹ÃËÏÝáéõû%/1A[_amswƒ‰‘•³µ¹»Çãåëñ÷û
!
+
-
=
?
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§22³2·2É2Ë2Ï2Ñ2é2í2ó2ù23%3+3/353A3G3[3_3g3k3s3y33ƒ3¡3£33¹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‹666¯6¹6»6Í6Ñ6ã6é6÷67777?7E7I7O7]7a7u777£7©7«7É7Õ7ß7ñ7ó7÷788!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@‡@‘@£@©@±@·@½@Û@ß@ë@÷@ù@ AAAA!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 DDD#D)D;D?DEDKDQDSDYDeDoDƒDD¡D¥D«DD½D¿DÉD×DÛDùDûDEEE+E1EAEIESEUEaEwE}EEE£EE¯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 +#)-?GQW]eo{‰“™›·¹ÃËÏÝáéõû%/1A[_amswƒ‰‘•³µ¹»Çãåëñ÷û
!
+
-
=
?
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§22³2·2É2Ë2Ï2Ñ2é2í2ó2ù23%3+3/353A3G3[3_3g3k3s3y33ƒ3¡3£33¹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‹666¯6¹6»6Í6Ñ6ã6é6÷67777?7E7I7O7]7a7u777£7©7«7É7Õ7ß7ñ7ó7÷788!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@‡@‘@£@©@±@·@½@Û@ß@ë@÷@ù@ AAAA!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 DDD#D)D;D?DEDKDQDSDYDeDoDƒDD¡D¥D«DD½D¿DÉD×DÛDùDûDEEE+E1EAEIESEUEaEwE}EEE£EE¯E»EÇE +j +
þp'dø'úö_0¥
lÚòb^xGÓf +ŠÀÝkÖÝGßÙØê|° +à·‘J Ö.<EÉ‹yçÇ™:%íÓõ\cXÖœ÷¢ÞùÞ +#ÐÔò`ýÞ·eå +N’Q² + + + + + + + + + + + + + + + + + + + + + + + + + + +—IÔJ2Œ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$T2(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Œ`0e24y‹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¬€2tG3t€ 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|PV×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 NC¾¶Gç*b]¦Å3bV$²¼fCÑhÕ;i¦ž¸|Õ¯>!1뤘òj^|›E²ÕŒ²§W_/OÛR™|X_ò¥öQ†!/[j®ƒ4mXKïþ¿s]ÛÄ—*…ólFB³ÁW—P5±·Ç<…mlýΰɢwîÃk7ú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.10UAndroid0
160104124053Z
351230124053Z0v10 UUS10U +California10U +Google, Inc.10UAndroid1)0'U Android Software Attestation Key0Ÿ0
*†H†÷
+California10U
Mountain View10U +Google, Inc.10UAndroid0
160104123108Z
351230123108Z0c10 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid0Ÿ0
*†H†÷
+*†HÎ=¡DB +*†HÎ=0˜10 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0
160111004609Z
260108004609Z0ˆ10 UUS10U +California10U +Google, Inc.10UAndroid1;09U2Android Keystore Software Attestation Intermediate0Y0*†HÎ=*†HÎ=B +*†HÎ=H +*†HÎ=0˜10 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0
160111004350Z
360106004350Z0˜10 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*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.10UAndroid0
160104124053Z
351230124053Z0v10 UUS10U California10U @@ -7005,293 +4838,182 @@ California10U
Mountain View10U Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0
160111004350Z
360106004350Z0˜10 UUS10U California10U
Mountain View10U Google, Inc.10UAndroid1301U*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(), ¶ms, &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(), ¶ms, 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----- |