| /* |
| * 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 "ecdsa_keymaster1_operation.h" |
| |
| #include <memory> |
| |
| #include <keymaster/android_keymaster_utils.h> |
| #include <keymaster/km_openssl/openssl_err.h> |
| #include <keymaster/km_openssl/openssl_utils.h> |
| #include <keymaster/legacy_support/ec_keymaster1_key.h> |
| |
| using std::unique_ptr; |
| |
| namespace keymaster { |
| |
| keymaster_error_t EcdsaKeymaster1WrappedOperation::Begin(EVP_PKEY* ecdsa_key, |
| const AuthorizationSet& input_params) { |
| Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key); |
| if (!key_data) |
| return KM_ERROR_UNKNOWN_ERROR; |
| |
| // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified. Also change |
| // KM_PAD_ECDSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll |
| // pass |
| // to the hardware module. The regular Ecdsa*Operation classes will do software digesting and |
| // padding where we've told the HW not to. |
| // |
| // The reason we don't change KM_PAD_ECDSA_PKCS1_1_5_SIGN or KM_PAD_ECDSA_PKCS1_1_5_ENCRYPT to |
| // KM_PAD_NONE is because the hardware can to those padding modes, since they don't involve |
| // digesting. |
| // |
| // We also cache in the key the padding value that we expect to be passed to the engine crypto |
| // operation. This just allows us to double-check that the correct padding value is reaching |
| // that layer. |
| AuthorizationSet begin_params(input_params); |
| int pos = begin_params.find(TAG_DIGEST); |
| if (pos == -1) |
| return KM_ERROR_UNSUPPORTED_DIGEST; |
| begin_params[pos].enumerated = KM_DIGEST_NONE; |
| |
| return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material, |
| &begin_params, nullptr /* out_params */, &operation_handle_); |
| } |
| |
| keymaster_error_t |
| EcdsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* ecdsa_key, |
| const AuthorizationSet& input_params) { |
| Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key); |
| if (!key_data) { |
| LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0); |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| key_data->op_handle = operation_handle_; |
| key_data->finish_params.Reinitialize(input_params); |
| |
| return KM_ERROR_OK; |
| } |
| |
| keymaster_error_t EcdsaKeymaster1WrappedOperation::Abort() { |
| return engine_->device()->abort(engine_->device(), operation_handle_); |
| } |
| |
| keymaster_error_t EcdsaKeymaster1WrappedOperation::GetError(EVP_PKEY* ecdsa_key) { |
| Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key); |
| if (!key_data) |
| return KM_ERROR_UNKNOWN_ERROR; |
| return key_data->error; |
| } |
| |
| static EVP_PKEY* GetEvpKey(const EcdsaKeymaster1Key& key, keymaster_error_t* error) { |
| if (!key.key()) { |
| *error = KM_ERROR_UNKNOWN_ERROR; |
| return nullptr; |
| } |
| |
| UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new()); |
| if (!key.InternalToEvp(pkey.get())) { |
| *error = KM_ERROR_UNKNOWN_ERROR; |
| return nullptr; |
| } |
| return pkey.release(); |
| } |
| |
| OperationPtr EcdsaKeymaster1OperationFactory::CreateOperation(Key&& key, |
| const AuthorizationSet& begin_params, |
| keymaster_error_t* error) { |
| keymaster_digest_t digest; |
| if (!GetAndValidateDigest(begin_params, key, &digest, error)) return nullptr; |
| |
| const EcdsaKeymaster1Key& ecdsa_km1_key = static_cast<EcdsaKeymaster1Key&>(key); |
| unique_ptr<EVP_PKEY, EVP_PKEY_Delete> ecdsa(GetEvpKey(ecdsa_km1_key, error)); |
| if (!ecdsa) return nullptr; |
| |
| switch (purpose_) { |
| case KM_PURPOSE_SIGN: |
| return OperationPtr(new EcdsaKeymaster1Operation<EcdsaSignOperation>( |
| key.hw_enforced_move(), key.sw_enforced_move(), digest, ecdsa.release(), engine_)); |
| default: |
| LOG_E( |
| "Bug: Pubkey operation requested. Those should be handled by normal ECDSA operations.", |
| 0); |
| *error = KM_ERROR_UNSUPPORTED_PURPOSE; |
| return nullptr; |
| } |
| } |
| |
| static const keymaster_digest_t supported_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}; |
| |
| const keymaster_digest_t* |
| EcdsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const { |
| *digest_count = array_length(supported_digests); |
| return supported_digests; |
| } |
| |
| const keymaster_padding_t* |
| EcdsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const { |
| *padding_mode_count = 0; |
| return nullptr; |
| } |
| |
| } // namespace keymaster |