Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/aasdk/Version.hpp"
install(FILES
"${CMAKE_CURRENT_SOURCE_DIR}/cert/headunit.crt"
"${CMAKE_CURRENT_SOURCE_DIR}/cert/headunit.key"
DESTINATION /etc/openauto
PERMISSIONS OWNER_READ GROUP_READ
DESTINATION /etc/aasdk
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ
COMPONENT runtime
)

Expand Down
34 changes: 34 additions & 0 deletions debian/postinst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,40 @@ export DEBIAN_FRONTEND=noninteractive

case "$1" in
configure)
cert_dir="/etc/aasdk"
legacy_dir="/etc/openauto"
cert_file="$cert_dir/headunit.crt"
key_file="$cert_dir/headunit.key"

# Ensure target cert directory exists.
mkdir -p "$cert_dir"
chmod 755 "$cert_dir" || true

# Migrate from the old location if needed.
if [ ! -f "$cert_file" ] && [ -f "$legacy_dir/headunit.crt" ]; then
cp -f "$legacy_dir/headunit.crt" "$cert_file"
fi

if [ ! -f "$key_file" ] && [ -f "$legacy_dir/headunit.key" ]; then
cp -f "$legacy_dir/headunit.key" "$key_file"
fi

# Use pi group when available so non-root Crankshaft/OpenAuto runtimes can read certs.
cert_group="root"
if getent group pi >/dev/null 2>&1; then
cert_group="pi"
fi

if [ -f "$cert_file" ]; then
chown root:"$cert_group" "$cert_file" || true
chmod 640 "$cert_file" || true
fi

if [ -f "$key_file" ]; then
chown root:"$cert_group" "$key_file" || true
chmod 640 "$key_file" || true
fi

# Update the dynamic linker cache
if [ -x /sbin/ldconfig ]; then
/sbin/ldconfig || true
Expand Down
5 changes: 4 additions & 1 deletion src/Channel/Control/ControlServiceChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ namespace aasdk {

void ControlServiceChannel::sendVersionRequest(SendPromise::Pointer promise) {
AASDK_LOG_CHANNEL_CONTROL(debug, "sendVersionRequest()");
AASDK_LOG(info) << "[ControlServiceChannel] sendVersionRequest major=" << AASDK_MAJOR
<< " minor=" << AASDK_MINOR;

auto message(std::make_shared<messenger::Message>(channelId_, messenger::EncryptionType::PLAIN,
messenger::MessageType::SPECIFIC));
Expand All @@ -53,6 +55,7 @@ namespace aasdk {

void ControlServiceChannel::sendHandshake(common::Data handshakeBuffer, SendPromise::Pointer promise) {
AASDK_LOG_CHANNEL_CONTROL(debug, "sendHandshake()");
AASDK_LOG(info) << "[ControlServiceChannel] sendHandshake bytes=" << handshakeBuffer.size();
auto message(std::make_shared<messenger::Message>(channelId_, messenger::EncryptionType::PLAIN,
messenger::MessageType::SPECIFIC));
message->insertPayload(
Expand Down Expand Up @@ -193,7 +196,7 @@ namespace aasdk {
messenger::MessageId messageId(message->getPayload());
common::DataConstBuffer payload(message->getPayload(), messageId.getSizeOf());

AASDK_LOG(debug) << "[ControlServiceChannel] MessageId: " << messageId.getId();
AASDK_LOG(info) << "[ControlServiceChannel] MessageId: " << messageId.getId();

switch (messageId.getId()) {
case aap_protobuf::service::control::message::ControlMessageType::MESSAGE_VERSION_RESPONSE:
Expand Down
57 changes: 35 additions & 22 deletions src/Messenger/Cryptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ KAwp3tIHPoJOQiKNQ3/qks5km/9dujUGU2ARiU3qmxLMdgegFz8e\n\
static std::string loadCertificate() {
// Try paths in order of preference
std::vector<std::string> certPaths = {
"/etc/openauto/headunit.crt", // Installed system path
"/etc/aasdk/headunit.crt", // Installed system path
"/etc/openauto/headunit.crt", // Legacy path (backward compatibility)
"/usr/share/aasdk/cert/headunit.crt", // Alternative system path
"./cert/headunit.crt", // Development path
"../cert/headunit.crt" // Alternative development path
Expand All @@ -117,7 +118,8 @@ KAwp3tIHPoJOQiKNQ3/qks5km/9dujUGU2ARiU3qmxLMdgegFz8e\n\
static std::string loadPrivateKey() {
// Try paths in order of preference
std::vector<std::string> keyPaths = {
"/etc/openauto/headunit.key", // Installed system path
"/etc/aasdk/headunit.key", // Installed system path
"/etc/openauto/headunit.key", // Legacy path (backward compatibility)
"/usr/share/aasdk/cert/headunit.key", // Alternative system path
"./cert/headunit.key", // Development path
"../cert/headunit.key" // Alternative development path
Expand Down Expand Up @@ -261,37 +263,42 @@ KAwp3tIHPoJOQiKNQ3/qks5km/9dujUGU2ARiU3qmxLMdgegFz8e\n\
}

size_t Cryptor::decrypt(common::Data &output, const common::DataConstBuffer &buffer, int frameLength) {
int overhead = 29;
int length = frameLength - overhead;
std::lock_guard<decltype(mutex_)> lock(mutex_);

this->write(buffer);
const size_t beginOffset = output.size();

size_t totalReadSize = 0; // Initialise
size_t availableBytes = length;
size_t readBytes = (availableBytes - totalReadSize) > 2048 ? 2048 : availableBytes -
totalReadSize; // Calculate How many Bytes to Read
output.resize(output.size() +
readBytes); // Resize Output to match the bytes we want to read

// We try to be a bit more explicit here, using the frame length from the frame itself rather than just blindly reading from the SSL buffer.
size_t totalReadSize = 0;
while (true) {
const size_t readBytes = 2048;
output.resize(beginOffset + totalReadSize + readBytes);

while (readBytes > 0) {
const auto &currentBuffer = common::DataBuffer(output, totalReadSize + beginOffset);
auto readSize = sslWrapper_->sslRead(ssl_, currentBuffer.data, currentBuffer.size);
const auto readSize = sslWrapper_->sslRead(ssl_, currentBuffer.data, currentBuffer.size);

if (readSize <= 0) {
throw error::Error(error::ErrorCode::SSL_READ, sslWrapper_->getError(ssl_, readSize));
const auto nativeError = sslWrapper_->getError(ssl_, readSize);

if (nativeError == SSL_ERROR_WANT_READ || nativeError == SSL_ERROR_WANT_WRITE) {
AASDK_LOG(debug) << "[Cryptor] SSL decrypt drained"
<< " frameLength=" << frameLength
<< " totalReadSize=" << totalReadSize
<< " requestedReadBytes=" << readBytes
<< " sslError=" << nativeError;
output.resize(beginOffset + totalReadSize);
return totalReadSize;
}

const std::string info = "decrypt sslRead<=0"
" frameLength=" + std::to_string(frameLength) +
" totalReadSize=" + std::to_string(totalReadSize) +
" requestedReadBytes=" + std::to_string(readBytes) +
" returnCode=" + std::to_string(readSize);
throw error::Error(error::ErrorCode::SSL_READ, nativeError, info);
}

totalReadSize += readSize;
availableBytes = sslWrapper_->getAvailableBytes(ssl_);
readBytes = (length - totalReadSize) > 2048 ? 2048 : length - totalReadSize;
output.resize(output.size() + readBytes);
totalReadSize += static_cast<size_t>(readSize);
}

return totalReadSize;
}

common::Data Cryptor::readHandshakeBuffer() {
Expand Down Expand Up @@ -320,7 +327,13 @@ KAwp3tIHPoJOQiKNQ3/qks5km/9dujUGU2ARiU3qmxLMdgegFz8e\n\
const auto readSize = sslWrapper_->bioRead(bIOs_.second, currentBuffer.data, currentBuffer.size);

if (readSize <= 0) {
throw error::Error(error::ErrorCode::SSL_BIO_READ, sslWrapper_->getError(ssl_, readSize));
const auto nativeError = sslWrapper_->getError(ssl_, readSize);
const std::string info = "read bioRead<=0"
" pendingSize=" + std::to_string(pendingSize) +
" totalReadSize=" + std::to_string(totalReadSize) +
" currentBufferSize=" + std::to_string(currentBuffer.size) +
" returnCode=" + std::to_string(readSize);
throw error::Error(error::ErrorCode::SSL_BIO_READ, nativeError, info);
}

totalReadSize += readSize;
Expand Down
54 changes: 43 additions & 11 deletions src/Messenger/MessageInStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// along with aasdk. If not, see <http://www.gnu.org/licenses/>.

#include <aasdk/Messenger/MessageInStream.hpp>
#include <aasdk/Messenger/MessageId.hpp>
#include <aasdk/Error/Error.hpp>
#include <aasdk/Common/Log.hpp>
#include <aasdk/Common/ModernLogger.hpp>
Expand Down Expand Up @@ -59,9 +60,14 @@ namespace aasdk::messenger {
void MessageInStream::receiveFrameHeaderHandler(const common::DataConstBuffer &buffer) {
FrameHeader frameHeader(buffer);

AASDK_LOG(debug) << "[MessageInStream] Processing Frame Header: Ch "
AASDK_LOG(info) << "[MessageInStream] Processing Frame Header: Ch "
<< channelIdToString(frameHeader.getChannelId()) << " Fr "
<< frameTypeToString(frameHeader.getType());
<< frameTypeToString(frameHeader.getType())
<< " Enc " << (frameHeader.getEncryptionType() == EncryptionType::ENCRYPTED ? "ENCRYPTED" : "PLAIN")
<< " Msg " << (frameHeader.getMessageType() == MessageType::CONTROL ? "CONTROL" : "SPECIFIC")
<< " Raw[0]=0x" << std::hex << static_cast<int>(buffer.cdata[0])
<< " Raw[1]=0x" << static_cast<int>(buffer.cdata[1])
<< std::dec;

isValidFrame_ = true;

Expand Down Expand Up @@ -125,20 +131,46 @@ namespace aasdk::messenger {

FrameSize frameSize(buffer);
frameSize_ = (int) frameSize.getFrameSize();
AASDK_LOG(info) << "[MessageInStream] Frame size parsed: frameSize=" << frameSize.getFrameSize()
<< " totalSize=" << frameSize.getTotalSize();
transport_->receive(frameSize.getFrameSize(), std::move(transportPromise));
}

void MessageInStream::receiveFramePayloadHandler(const common::DataConstBuffer &buffer) {
AASDK_LOG(info) << "[MessageInStream] Payload handler: ch=" << channelIdToString(message_->getChannelId())
<< " enc=" << (message_->getEncryptionType() == EncryptionType::ENCRYPTED ? "ENCRYPTED" : "PLAIN")
<< " msg=" << (message_->getType() == MessageType::CONTROL ? "CONTROL" : "SPECIFIC")
<< " frameType=" << frameTypeToString(thisFrameType_)
<< " frameSize=" << frameSize_
<< " payloadBytes=" << buffer.size
<< " cryptorActive=" << (cryptor_->isActive() ? "true" : "false");

if (message_->getEncryptionType() == EncryptionType::ENCRYPTED) {
try {
cryptor_->decrypt(message_->getPayload(), buffer, frameSize_);
}
catch (const error::Error &e) {
AASDK_LOG_MESSENGER(debug, "Rejecting message.");
message_.reset();
promise_->reject(e);
promise_.reset();
return;
if (!cryptor_->isActive()) {
// Some devices deliver raw TLS records on control before cryptor activation.
// Only synthesize ENCAPSULATED_SSL for TLS-looking records to avoid
// misclassifying regular control payloads (e.g. version responses).
const bool looksLikeTlsRecord =
(buffer.size >= 2) &&
(buffer.cdata[0] >= 0x14 && buffer.cdata[0] <= 0x17) &&
(buffer.cdata[1] == 0x03);

if (message_->getChannelId() == ChannelId::CONTROL && looksLikeTlsRecord) {
message_->insertPayload(messenger::MessageId(3).getData());
}

message_->insertPayload(buffer);
} else {
try {
cryptor_->decrypt(message_->getPayload(), buffer, frameSize_);
}
catch (const error::Error &e) {
AASDK_LOG_MESSENGER(debug, "Rejecting message.");
message_.reset();
promise_->reject(e);
promise_.reset();
return;
}
}
} else {
message_->insertPayload(buffer);
Expand Down
44 changes: 43 additions & 1 deletion src/Transport/SSLWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// along with aasdk. If not, see <http://www.gnu.org/licenses/>.

#include <string>
#include <cerrno>
#include <cstring>
#if defined(__has_include) && __has_include(<openssl/engine.h>) && !defined(OPENSSL_NO_ENGINE)
#include <openssl/engine.h>
#define HAVE_ENGINE_H
Expand All @@ -32,6 +34,35 @@
namespace aasdk {
namespace transport {

static auto sslErrorToString(int sslErrorCode) -> const char* {
switch (sslErrorCode) {
case SSL_ERROR_NONE:
return "SSL_ERROR_NONE";
case SSL_ERROR_SSL:
return "SSL_ERROR_SSL";
case SSL_ERROR_WANT_READ:
return "SSL_ERROR_WANT_READ";
case SSL_ERROR_WANT_WRITE:
return "SSL_ERROR_WANT_WRITE";
case SSL_ERROR_WANT_X509_LOOKUP:
return "SSL_ERROR_WANT_X509_LOOKUP";
case SSL_ERROR_SYSCALL:
return "SSL_ERROR_SYSCALL";
case SSL_ERROR_ZERO_RETURN:
return "SSL_ERROR_ZERO_RETURN";
#if defined(SSL_ERROR_WANT_CONNECT)
case SSL_ERROR_WANT_CONNECT:
return "SSL_ERROR_WANT_CONNECT";
#endif
#if defined(SSL_ERROR_WANT_ACCEPT)
case SSL_ERROR_WANT_ACCEPT:
return "SSL_ERROR_WANT_ACCEPT";
#endif
default:
return "SSL_ERROR_UNKNOWN";
}
}

SSLWrapper::SSLWrapper() {
SSL_library_init();
SSL_load_error_strings(); // Optional: Can also be removed if not needed.
Expand Down Expand Up @@ -187,10 +218,21 @@ namespace aasdk {
}

int SSLWrapper::getError(SSL *ssl, int returnCode) {
const int sslErrorCode = SSL_get_error(ssl, returnCode);
const int savedErrno = errno;

AASDK_LOG(error) << "[SSLWrapper] getError returnCode=" << returnCode
<< " ssl_error=" << sslErrorCode
<< "(" << sslErrorToString(sslErrorCode) << ")"
<< " errno=" << savedErrno
<< "(" << std::strerror(savedErrno) << ")"
<< " state="
<< (ssl ? SSL_state_string_long(ssl) : "<null-ssl>");

while (auto err = ERR_get_error()) {
AASDK_LOG(error) << "[SSLWrapper] SSL Error " << ERR_error_string(err, NULL);
}
return SSL_get_error(ssl, returnCode);
return sslErrorCode;
}

}
Expand Down
42 changes: 38 additions & 4 deletions src/Transport/USBTransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// along with aasdk. If not, see <http://www.gnu.org/licenses/>.

#include <aasdk/Transport/USBTransport.hpp>
#include <aasdk/Common/Log.hpp>


namespace aasdk {
Expand All @@ -26,11 +27,24 @@ namespace aasdk {
: Transport(ioService), aoapDevice_(std::move(aoapDevice)) {}

void USBTransport::enqueueReceive(common::DataBuffer buffer) {
const auto inEndpoint = aoapDevice_->getInEndpoint().getAddress();
AASDK_LOG(info) << "[USBTransport] enqueueReceive endpoint=0x" << std::hex
<< static_cast<int>(inEndpoint) << std::dec
<< " requestedBytes=" << buffer.size;

auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(receiveStrand_);
usbEndpointPromise->then([this, self = this->shared_from_this()](auto bytesTransferred) {
usbEndpointPromise->then([this, self = this->shared_from_this(), inEndpoint](auto bytesTransferred) {
AASDK_LOG(info) << "[USBTransport] receiveComplete endpoint=0x"
<< std::hex << static_cast<int>(inEndpoint)
<< std::dec << " bytesTransferred=" << bytesTransferred;
this->receiveHandler(bytesTransferred);
},
[this, self = this->shared_from_this()](auto e) {
[this, self = this->shared_from_this(), inEndpoint](auto e) {
AASDK_LOG(warning) << "[USBTransport] receiveError endpoint=0x"
<< std::hex << static_cast<int>(inEndpoint)
<< std::dec << " code=" << static_cast<int>(e.getCode())
<< " native=" << e.getNativeCode()
<< " what=" << e.what();
this->rejectReceivePromises(e);
});

Expand All @@ -42,12 +56,32 @@ namespace aasdk {
}

void USBTransport::doSend(SendQueue::iterator queueElement, common::Data::size_type offset) {
const auto outEndpoint = aoapDevice_->getOutEndpoint().getAddress();
const auto remainingBytes = queueElement->first.size() - offset;
AASDK_LOG(info) << "[USBTransport] doSend endpoint=0x" << std::hex
<< static_cast<int>(outEndpoint) << std::dec
<< " offset=" << offset
<< " remainingBytes=" << remainingBytes
<< " totalMessageBytes=" << queueElement->first.size();

auto usbEndpointPromise = usb::IUSBEndpoint::Promise::defer(sendStrand_);
usbEndpointPromise->then(
[this, self = this->shared_from_this(), queueElement, offset](size_t bytesTransferred) mutable {
[this, self = this->shared_from_this(), queueElement, offset, outEndpoint](size_t bytesTransferred) mutable {
AASDK_LOG(info) << "[USBTransport] sendComplete endpoint=0x" << std::hex
<< static_cast<int>(outEndpoint) << std::dec
<< " offset=" << offset
<< " bytesTransferred=" << bytesTransferred
<< " totalMessageBytes=" << queueElement->first.size();
this->sendHandler(queueElement, offset, bytesTransferred);
},
[this, self = this->shared_from_this(), queueElement](const error::Error &e) mutable {
[this, self = this->shared_from_this(), queueElement, offset, outEndpoint](const error::Error &e) mutable {
AASDK_LOG(warning) << "[USBTransport] sendError endpoint=0x" << std::hex
<< static_cast<int>(outEndpoint) << std::dec
<< " offset=" << offset
<< " totalMessageBytes=" << queueElement->first.size()
<< " code=" << static_cast<int>(e.getCode())
<< " native=" << e.getNativeCode()
<< " what=" << e.what();
queueElement->second->reject(e);
sendQueue_.erase(queueElement);

Expand Down
Loading
Loading