217 lines
7.0 KiB
C++
217 lines
7.0 KiB
C++
/*
|
|
* Copyright 2020 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 "common/libs/security/keymaster_channel_windows.h"
|
|
|
|
#include <windows.h>
|
|
|
|
#include <errhandlingapi.h>
|
|
#include <fileapi.h>
|
|
#include <handleapi.h>
|
|
#include <namedpipeapi.h>
|
|
#include <chrono>
|
|
#include <cstdlib>
|
|
#include <thread>
|
|
|
|
#include <android-base/logging.h>
|
|
#include <keymaster/android_keymaster_utils.h>
|
|
|
|
namespace cuttlefish {
|
|
using keymaster::keymaster_message;
|
|
|
|
std::unique_ptr<KeymasterWindowsChannel> KeymasterWindowsChannel::Create(
|
|
HANDLE pipe_handle) {
|
|
auto keymaster_channel =
|
|
std::unique_ptr<KeymasterWindowsChannel>(new KeymasterWindowsChannel());
|
|
if (!keymaster_channel->WaitForConnection(pipe_handle)) {
|
|
return nullptr;
|
|
}
|
|
|
|
return keymaster_channel;
|
|
}
|
|
|
|
bool KeymasterWindowsChannel::WaitForConnection(HANDLE pipe_handle) {
|
|
assert(pipe_handle_ == NULL);
|
|
pipe_handle_ = pipe_handle;
|
|
|
|
DWORD flags;
|
|
if (GetNamedPipeInfo(pipe_handle_,
|
|
/*lpFlags= */ &flags,
|
|
/*lpOutBufferSize= */ NULL,
|
|
/* lpInBufferSize= */ NULL,
|
|
/* lpMaxInstances= */ NULL) == 0) {
|
|
LOG(ERROR)
|
|
<< "Could not query Keymaster named pipe handle info. Got error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
|
|
if ((flags & PIPE_SERVER_END) == 0) {
|
|
LOG(ERROR) << "Keymaster handle is not the server end of a named pipe!";
|
|
return false;
|
|
}
|
|
|
|
// Create the event object
|
|
HANDLE event_handle =
|
|
CreateEventA(/* lpEventAttributes= */ NULL, /* bManualReset= */ true,
|
|
/* bInitialState= */ 0, /* lpName= */ NULL);
|
|
if (event_handle == NULL) {
|
|
LOG(ERROR)
|
|
<< "Error: Could not create keymaster event object. Got error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
pipe_overlapped_.hEvent = event_handle;
|
|
|
|
// Wait for client to connect to the pipe
|
|
ConnectNamedPipe(pipe_handle_, &pipe_overlapped_);
|
|
LOG(INFO) << "Listening to existing keymaster pipe handle.";
|
|
|
|
if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
|
|
LOG(ERROR) << "Could not wait for Keymaster pipe's overlapped to be "
|
|
"signalled. Got Windows error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
if (!ResetEvent(pipe_overlapped_.hEvent)) {
|
|
LOG(ERROR) << "Could not reset Keymaster pipe's overlapped. Got Windows "
|
|
"error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
KeymasterWindowsChannel::~KeymasterWindowsChannel() {
|
|
if (pipe_handle_) {
|
|
CloseHandle(pipe_handle_);
|
|
}
|
|
|
|
if (pipe_overlapped_.hEvent) {
|
|
CloseHandle(pipe_overlapped_.hEvent);
|
|
}
|
|
}
|
|
|
|
bool KeymasterWindowsChannel::SendRequest(
|
|
AndroidKeymasterCommand command, const keymaster::Serializable& message) {
|
|
return SendMessage(command, false, message);
|
|
}
|
|
|
|
bool KeymasterWindowsChannel::SendResponse(
|
|
AndroidKeymasterCommand command, const keymaster::Serializable& message) {
|
|
return SendMessage(command, true, message);
|
|
}
|
|
|
|
bool KeymasterWindowsChannel::SendMessage(
|
|
AndroidKeymasterCommand command, bool is_response,
|
|
const keymaster::Serializable& message) {
|
|
auto payload_size = message.SerializedSize();
|
|
if (payload_size > 1024 * 1024) {
|
|
LOG(WARNING) << "Sending large message with id: " << command << " and size "
|
|
<< payload_size;
|
|
}
|
|
|
|
auto to_send = CreateKeymasterMessage(command, is_response, payload_size);
|
|
message.Serialize(to_send->payload, to_send->payload + payload_size);
|
|
auto write_size = payload_size + sizeof(keymaster_message);
|
|
auto to_send_bytes = reinterpret_cast<const char*>(to_send.get());
|
|
if (!WriteFile(pipe_handle_, to_send_bytes, write_size, NULL,
|
|
&pipe_overlapped_) &&
|
|
GetLastError() != ERROR_IO_PENDING) {
|
|
LOG(ERROR) << "Could not write Keymaster Message. Got Windows error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
|
|
// Vsock pipes are overlapped (asynchronous) and we need to wait for the
|
|
// overlapped event to be signaled.
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject#return-value
|
|
if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
|
|
LOG(ERROR) << "Could not wait for Keymaster pipe's overlapped to be "
|
|
"signalled. Got Windows error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
if (!ResetEvent(pipe_overlapped_.hEvent)) {
|
|
LOG(ERROR) << "Could not reset Keymaster pipe's overlapped. Got Windows "
|
|
"error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool KeymasterWindowsChannel::ReadFromPipe(LPVOID buffer, DWORD size) {
|
|
if (ReadFile(pipe_handle_, buffer, size, NULL, &pipe_overlapped_) == FALSE) {
|
|
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
|
LOG(INFO) << "Keymaster pipe was closed.";
|
|
return false;
|
|
} else if (GetLastError() != ERROR_IO_PENDING) {
|
|
LOG(ERROR) << "Could not read Keymaster message. Got Windows error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
|
|
// Wait for the asynchronous read to finish.
|
|
DWORD unused_bytes_read;
|
|
if (GetOverlappedResult(pipe_handle_, &pipe_overlapped_, &unused_bytes_read,
|
|
/*bWait=*/TRUE) == FALSE) {
|
|
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
|
LOG(INFO) << "Keymaster pipe was closed.";
|
|
return false;
|
|
}
|
|
|
|
LOG(ERROR) << "Error receiving Keymaster data. Got Windows error code "
|
|
<< GetLastError();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (ResetEvent(pipe_overlapped_.hEvent) == 0) {
|
|
LOG(ERROR) << "Error calling ResetEvent for Keymaster data. Got "
|
|
"Windows error code "
|
|
<< GetLastError();
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ManagedKeymasterMessage KeymasterWindowsChannel::ReceiveMessage() {
|
|
struct keymaster_message message_header;
|
|
if (!ReadFromPipe(&message_header, sizeof(message_header))) {
|
|
return {};
|
|
}
|
|
|
|
if (message_header.payload_size > 1024 * 1024) {
|
|
LOG(WARNING) << "Received large message with id: " << message_header.cmd
|
|
<< " and size " << message_header.payload_size;
|
|
}
|
|
|
|
auto message =
|
|
CreateKeymasterMessage(message_header.cmd, message_header.is_response,
|
|
message_header.payload_size);
|
|
auto message_bytes = reinterpret_cast<char*>(message->payload);
|
|
|
|
if (!ReadFromPipe(message_bytes, message->payload_size)) {
|
|
return {};
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
} // namespace cuttlefish
|