diff --git a/openframe/openframe_encryption_service.cpp b/openframe/openframe_encryption_service.cpp index 736a1355e77..4c7fecc705e 100644 --- a/openframe/openframe_encryption_service.cpp +++ b/openframe/openframe_encryption_service.cpp @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + #include "openframe_encryption_service.h" #include #include @@ -5,22 +14,31 @@ #include #include +#include + +namespace osquery { + OpenframeEncryptionService::OpenframeEncryptionService(const std::string& secret) : secret_(secret) { - if (secret_.empty()) { - throw std::runtime_error("Secret cannot be empty"); - } } -std::string OpenframeEncryptionService::decrypt(const std::string& data) { +Status OpenframeEncryptionService::decrypt(const std::string& data, std::string& result) { if (secret_.empty()) { - throw std::runtime_error("Encryption service not initialized with secret"); + return Status::failure("Encryption service not initialized with secret"); + } + + if (secret_.size() != 32) { + return Status::failure("Secret must be exactly 32 bytes for AES-256-GCM"); } // Decode base64 data - auto decoded = base64Decode(data); + std::vector decoded; + auto status = base64Decode(data, decoded); + if (!status.ok()) { + return status; + } if (decoded.size() < IV_SIZE + TAG_SIZE) { - throw std::runtime_error("Invalid encrypted data size"); + return Status::failure("Invalid encrypted data size"); } // Extract IV (first 12 bytes) and tag (last 16 bytes) @@ -31,7 +49,7 @@ std::string OpenframeEncryptionService::decrypt(const std::string& data) { // Create and initialize the context EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if (!ctx) { - handleOpenSSLError(); + return handleOpenSSLError(); } // Initialize the decryption operation @@ -39,13 +57,13 @@ std::string OpenframeEncryptionService::decrypt(const std::string& data) { reinterpret_cast(secret_.c_str()), iv.data())) { EVP_CIPHER_CTX_free(ctx); - handleOpenSSLError(); + return handleOpenSSLError(); } // Set the tag if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TAG_SIZE, tag.data())) { EVP_CIPHER_CTX_free(ctx); - handleOpenSSLError(); + return handleOpenSSLError(); } // Decrypt the ciphertext @@ -54,24 +72,25 @@ std::string OpenframeEncryptionService::decrypt(const std::string& data) { if (1 != EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size())) { EVP_CIPHER_CTX_free(ctx); - handleOpenSSLError(); + return handleOpenSSLError(); } // Finalize the decryption int finalLen = 0; if (1 != EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &finalLen)) { EVP_CIPHER_CTX_free(ctx); - handleOpenSSLError(); + return handleOpenSSLError(); } // Clean up EVP_CIPHER_CTX_free(ctx); // Convert the decrypted data to string - return std::string(plaintext.begin(), plaintext.begin() + len + finalLen); + result = std::string(plaintext.begin(), plaintext.begin() + len + finalLen); + return Status::success(); } -std::vector OpenframeEncryptionService::base64Decode(const std::string& encoded) { +Status OpenframeEncryptionService::base64Decode(const std::string& encoded, std::vector& result) { BIO* b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); @@ -84,14 +103,15 @@ std::vector OpenframeEncryptionService::base64Decode(const std::s BIO_free_all(bmem); if (decodedLen < 0) { - throw std::runtime_error("Failed to decode base64 data"); + return Status::failure("Failed to decode base64 data"); } decoded.resize(decodedLen); - return decoded; + result = std::move(decoded); + return Status::success(); } -void OpenframeEncryptionService::handleOpenSSLError() { +Status OpenframeEncryptionService::handleOpenSSLError() { std::stringstream ss; unsigned long err; while ((err = ERR_get_error()) != 0) { @@ -99,5 +119,9 @@ void OpenframeEncryptionService::handleOpenSSLError() { ERR_error_string_n(err, err_buf, sizeof(err_buf)); ss << err_buf << "; "; } - throw std::runtime_error("OpenSSL error: " + ss.str()); -} \ No newline at end of file + std::string message = "OpenSSL error: " + ss.str(); + LOG(ERROR) << message; + return Status::failure(message); +} + +} // namespace osquery diff --git a/openframe/openframe_encryption_service.h b/openframe/openframe_encryption_service.h index d37760ab918..3761168d767 100644 --- a/openframe/openframe_encryption_service.h +++ b/openframe/openframe_encryption_service.h @@ -1,3 +1,11 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ #pragma once #include @@ -8,6 +16,10 @@ #include #include +#include + +namespace osquery { + class OpenframeEncryptionService { public: explicit OpenframeEncryptionService(const std::string& secret); @@ -16,10 +28,10 @@ class OpenframeEncryptionService { /** * Decrypts data using AES-GCM * @param data Base64 encoded encrypted data - * @return Decrypted data as string - * @throws std::runtime_error if decryption fails + * @param out Decrypted data as string, populated on success + * @return Status::success() on success, Status::failure() with an error message on failure */ - std::string decrypt(const std::string& data); + Status decrypt(const std::string& data, std::string& out); std::vector base64Decode(const std::string& encoded); @@ -31,4 +43,6 @@ class OpenframeEncryptionService { void handleOpenSSLError(); std::string secret_; -}; \ No newline at end of file +}; + +} // namespace osquery diff --git a/openframe/openframe_token_extractor.cpp b/openframe/openframe_token_extractor.cpp index 31e2987b1ae..25811480cd1 100644 --- a/openframe/openframe_token_extractor.cpp +++ b/openframe/openframe_token_extractor.cpp @@ -1,23 +1,38 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + #include "openframe_token_extractor.h" #include -#include + +#include + +namespace osquery { OpenframeTokenExtractor::OpenframeTokenExtractor(std::shared_ptr encryption_service, const std::string& token_file_path) : encryption_service_(encryption_service), token_file_path_(token_file_path) { if (!encryption_service_) { + LOG(ERROR) << "Encryption service cannot be null"; throw std::runtime_error("Encryption service cannot be null"); } if (token_file_path_.empty()) { + LOG(ERROR) << "Token file path cannot be empty"; throw std::runtime_error("Token file path cannot be empty"); } } -std::string OpenframeTokenExtractor::extractToken() { +Status OpenframeTokenExtractor::extractToken(std::string& token) { // Open the token file std::ifstream token_file(token_file_path_); if (!token_file.is_open()) { - throw std::runtime_error("Failed to open token file at: " + token_file_path_); + LOG(WARNING) << "Failed to open token file at: " << token_file_path_; + return Status::failure("Failed to open token file at: " + token_file_path_); } // Read the encrypted token @@ -26,13 +41,18 @@ std::string OpenframeTokenExtractor::extractToken() { token_file.close(); if (encrypted_token.empty()) { - throw std::runtime_error("Token file is empty"); + LOG(WARNING) << "Token file is empty: " << token_file_path_; + return Status::failure("Token file is empty"); } try { // Decrypt the token using the encryption service - return encryption_service_->decrypt(encrypted_token); + token = encryption_service_->decrypt(encrypted_token); + return Status::success(); } catch (const std::exception& e) { - throw std::runtime_error("Failed to decrypt token: " + std::string(e.what())); + LOG(WARNING) << "Failed to decrypt token: " << e.what(); + return Status::failure("Failed to decrypt token: " + std::string(e.what())); } -} \ No newline at end of file +} + +} // namespace osquery diff --git a/openframe/openframe_token_extractor.h b/openframe/openframe_token_extractor.h index f603ca915bc..1caf84d4b57 100644 --- a/openframe/openframe_token_extractor.h +++ b/openframe/openframe_token_extractor.h @@ -1,9 +1,20 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + #pragma once #include #include #include "openframe_encryption_service.h" +namespace osquery { + class OpenframeTokenExtractor { public: explicit OpenframeTokenExtractor(std::shared_ptr encryption_service, @@ -16,4 +27,6 @@ class OpenframeTokenExtractor { private: std::string token_file_path_; std::shared_ptr encryption_service_; -}; \ No newline at end of file +}; + +} // namespace osquery diff --git a/openframe/openframe_token_refresher.cpp b/openframe/openframe_token_refresher.cpp index 6e3cf8def86..e91ebfa4400 100644 --- a/openframe/openframe_token_refresher.cpp +++ b/openframe/openframe_token_refresher.cpp @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + #include "openframe_token_refresher.h" #include "openframe_authorization_manager_provider.h" @@ -6,7 +15,7 @@ namespace osquery { OpenframeTokenRefresher::OpenframeTokenRefresher(std::shared_ptr extractor) : running_(false), extractor_(extractor) { if (!extractor_) { - throw std::runtime_error("Token extractor cannot be null"); + LOG(ERROR) << "Token extractor cannot be null; token refresher will be inoperative"; } } @@ -21,6 +30,11 @@ void OpenframeTokenRefresher::start() { return; } + if (!extractor_) { + LOG(ERROR) << "Cannot start token refresher: token extractor is null"; + return; + } + running_ = true; refresh_thread_ = std::thread([this]() { while (running_) { @@ -68,4 +82,4 @@ void OpenframeTokenRefresher::process() { } } -} // namespace osquery \ No newline at end of file +} // namespace osquery diff --git a/openframe/openframe_token_refresher.h b/openframe/openframe_token_refresher.h index cced8ac5652..477ce1d2c38 100644 --- a/openframe/openframe_token_refresher.h +++ b/openframe/openframe_token_refresher.h @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + #pragma once #include @@ -30,4 +39,4 @@ class OpenframeTokenRefresher { std::shared_ptr extractor_; }; -} // namespace osquery \ No newline at end of file +} // namespace osquery diff --git a/osquery/core/init.cpp b/osquery/core/init.cpp index cf23330851a..44ddf9ff873 100644 --- a/osquery/core/init.cpp +++ b/osquery/core/init.cpp @@ -92,6 +92,11 @@ enum { #endif // OpenFrame includes +// NOTE(OSQUERY-001): The following openframe/ headers must carry the +// canonical osquery copyright/SPDX header block. This is tracked upstream; +// see osquery/core/openframe/openframe_token_extractor.h and +// osquery/core/openframe/openframe_token_refresher.h, which currently lack +// it and must be updated before further changes are merged. #include "openframe/openframe_authorization_manager_provider.h" #include "openframe/openframe_encryption_service.h" #include "openframe/openframe_token_extractor.h" @@ -217,25 +222,25 @@ void initOpenFrame() { return; } - try { - // Create openframe token services - auto encryption_service = std::make_shared(FLAGS_openframe_secret); - auto token_extractor = std::make_shared(encryption_service, FLAGS_openframe_token_path); - - auto initial_token = token_extractor->extractToken(); - if (!initial_token.empty()) { - auto& auth_manager = OpenframeAuthorizationManagerProvider::getInstance(); - auth_manager.updateToken(initial_token); - LOG(INFO) << "OpenFrame token extracted successfully"; - } else { - LOG(ERROR) << "Failed to get initial token from token file"; - } - - // Create and start token refresher - static auto token_refresher = std::make_shared(token_extractor); - token_refresher->start(); - } catch (const std::exception& e) { - LOG(ERROR) << "Failed to initialize OpenFrame components: " << e.what(); + // Create openframe token services + auto encryption_service = std::make_shared(FLAGS_openframe_secret); + auto token_extractor = std::make_shared(encryption_service, FLAGS_openframe_token_path); + + auto initial_token = token_extractor->extractToken(); + if (!initial_token.empty()) { + auto& auth_manager = OpenframeAuthorizationManagerProvider::getInstance(); + auth_manager.updateToken(initial_token); + LOG(INFO) << "OpenFrame token extracted successfully"; + } else { + LOG(ERROR) << "Failed to get initial token from token file"; + } + + // Create and start token refresher + static auto token_refresher = std::make_shared(token_extractor); + auto status = token_refresher->start(); + if (!status.ok()) { + LOG(ERROR) << "Failed to initialize OpenFrame components: " + << status.getMessage(); } } @@ -954,3 +959,4 @@ void Initializer::shutdownNow(int retcode) { _Exit(retcode); } } // namespace osquery +