blob: 05e9c3e93ad15427c30feb0a2b7aa87b48a7372a [file] [log] [blame]
/*
* 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 "buffer.h"
#include "proto_utils.h"
#include <keymasterV4_0/key_param_output.h>
#include <android-base/logging.h>
#include <openssl/rsa.h>
#include <map>
#include <vector>
namespace android {
namespace hardware {
namespace keymaster {
// HAL
using ::android::hardware::keymaster::V4_0::Algorithm;
using ::android::hardware::keymaster::V4_0::ErrorCode;
// std
using std::map;
using std::pair;
using std::vector;
static const size_t kMaxChunkSize = 256;
class Operation {
public:
Operation(Algorithm algorithm) : _algorithm(algorithm), _buffer{} {
switch (_algorithm) {
case Algorithm::AES:
_blockSize = 16;
break;
case Algorithm::TRIPLE_DES:
_blockSize = 8;
break;
case Algorithm::RSA:
case Algorithm::EC:
case Algorithm::HMAC:
_blockSize = 0;
default:
break;
}
}
size_t remaining() const {
return _buffer.size();
}
void append(const hidl_vec<uint8_t>& input, uint32_t *consumed) {
_buffer.insert(_buffer.end(), input.begin(), input.end());
*consumed = input.size();
}
void peek(hidl_vec<uint8_t> *data) {
// Retain at least one full block; this is done so that when
// either GCM mode or PKCS7 padding are in use, the last block
// will be available to be consumed by final().
if (_buffer.size() <= _blockSize) {
*data = vector<uint8_t>();
return;
}
size_t retain;
if (_blockSize == 0) {
retain = 0;
} else {
retain = (_buffer.size() % _blockSize) + _blockSize;
}
const size_t count = std::min(_buffer.size() - retain, kMaxChunkSize);
*data = vector<uint8_t>(_buffer.begin(), _buffer.begin() + count);
}
ErrorCode advance(size_t count) {
if (count > _buffer.size()) {
LOG(ERROR) << "Attempt to advance " << count
<< " bytes, where occupancy is " << _buffer.size();
return ErrorCode::UNKNOWN_ERROR;
}
_buffer.erase(_buffer.begin(), _buffer.begin() + count);
return ErrorCode::OK;
}
void final(hidl_vec<uint8_t> *data) {
if (data != NULL) {
*data = _buffer;
}
_buffer.clear();
}
private:
Algorithm _algorithm;
size_t _blockSize;
vector<uint8_t> _buffer;
};
static map<uint64_t, Operation> buffer_map;
typedef map<uint64_t, Operation>::iterator buffer_item;
ErrorCode buffer_begin(uint64_t handle, Algorithm algorithm)
{
if (buffer_map.find(handle) != buffer_map.end()) {
LOG(ERROR) << "Duplicate operation handle " << handle
<< "returned by begin()";
// Final the existing op to potential mishandling of data.
buffer_final(handle, NULL);
return ErrorCode::UNKNOWN_ERROR;
}
buffer_map.insert(
pair<uint64_t, Operation>(handle, Operation(algorithm)));
return ErrorCode::OK;
}
size_t buffer_remaining(uint64_t handle) {
if (buffer_map.find(handle) == buffer_map.end()) {
LOG(ERROR) << "Remaining requested on absent operation: " << handle;
return 0;
}
const Operation &op = buffer_map.find(handle)->second;
return op.remaining();
}
ErrorCode buffer_append(uint64_t handle,
const hidl_vec<uint8_t>& input,
uint32_t *consumed)
{
if (buffer_map.find(handle) == buffer_map.end()) {
LOG(ERROR) << "Append requested on absent operation: " << handle;
return ErrorCode::UNKNOWN_ERROR;
}
Operation *op = &buffer_map.find(handle)->second;
op->append(input, consumed);
return ErrorCode::OK;
}
ErrorCode buffer_peek(uint64_t handle,
hidl_vec<uint8_t> *data)
{
if (buffer_map.find(handle) == buffer_map.end()) {
LOG(ERROR) << "Read requested on absent operation: " << handle;
return ErrorCode::UNKNOWN_ERROR;
}
Operation *op = &buffer_map.find(handle)->second;
op->peek(data);
return ErrorCode::OK;
}
ErrorCode buffer_advance(uint64_t handle, size_t count)
{
if (buffer_map.find(handle) == buffer_map.end()) {
LOG(ERROR) << "Read requested on absent operation: " << handle;
return ErrorCode::UNKNOWN_ERROR;
}
Operation *op = &buffer_map.find(handle)->second;
return op->advance(count);
}
ErrorCode buffer_final(uint64_t handle,
hidl_vec<uint8_t> *data)
{
if (buffer_map.find(handle) == buffer_map.end()) {
LOG(ERROR) << "Final requested on absent operation: " << handle;
return ErrorCode::UNKNOWN_ERROR;
}
Operation *op = &buffer_map.find(handle)->second;
op->final(data);
buffer_map.erase(handle);
return ErrorCode::OK;
}
} // namespace keymaster
} // hardware
} // android