Compare commits

...

23 Commits

Author SHA1 Message Date
Ivan Chvets
1c5909613f feat: Schema sync.
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-08-14 11:33:42 -04:00
Carsten Schafer
438309714f Merge pull request #418 from Telecominfraproject/WIFI-14953-add-entire-trust-chain-for-rtty
WIFI-14953 Add entire trust chain for rtty use
2025-08-06 11:00:04 -04:00
Carsten Schafer
a9130eeb75 Read from proper client cas file
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-06 09:13:04 -04:00
Carsten Schafer
33068fca9e Declare the variable
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 11:15:51 -04:00
Carsten Schafer
d329151f6c Fix typo
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 10:46:45 -04:00
Carsten Schafer
ec846006bb Add entire trust chain for rtty use
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 10:24:33 -04:00
i-chvets
242261de0a Merge pull request #413 from Telecominfraproject/WIFI-14820-fix_wifi_frames_schema_update
WIFI-14820: fix: Added new parameters to wifi-frames
2025-07-14 15:53:41 -04:00
Ivan Chvets
31a4edead5 fix: Added new parameters to wifi-frames
https://telecominfraproject.atlassian.net/browse/WIFI-14820

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-07-14 14:00:47 -04:00
Carsten Schafer
f7b697f219 Merge pull request #412 from Telecominfraproject/PKI2-132_feat_ap_reenroll_command-fix
fix: ucentral reenroll command is reenroll not re-enroll
2025-07-10 10:14:49 -04:00
Carsten Schafer
e020da75fc fix: ucentral reenroll command is reenroll not re-enroll
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-07-10 09:50:45 -04:00
i-chvets
89702f56e0 Merge pull request #411 from Telecominfraproject/PKI2-132_feat_ap_reenroll_command
feat: Added reneroll command handler.
2025-07-03 08:24:14 -04:00
Ivan Chvets
0ac97442c0 feat: Added reneroll command handler.
https://telecominfraproject.atlassian.net/browse/PKI2-132

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-07-02 17:53:54 -04:00
i-chvets
e38b4c8a13 Merge pull request #410 from Telecominfraproject/PKI2-131_feat_add_issuer_name
PKI2-131: feat: Added issuer name to certificate data.
2025-07-02 16:55:40 -04:00
Ivan Chvets
9c5bbee834 feat: Added issuer name to certificate data.
https://telecominfraproject.atlassian.net/browse/PKI2-131

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-07-02 16:32:46 -04:00
i-chvets
a5d1eebe6d Merge pull request #405 from Telecominfraproject/version_update
WIFI-14521: fix: Version update - release 4.0.0
2025-04-24 16:56:09 -04:00
Ivan Chvets
ee14f064c8 Merge branch 'master' of github.com:Telecominfraproject/wlan-cloud-ucentralgw into version_update 2025-04-24 16:36:14 -04:00
i-chvets
dbf52c1f23 Merge pull request #406 from Telecominfraproject/WIFI-14521-ci-changes
WIFI-14521 Update to ubuntu-latest for GH runner
2025-04-24 16:18:31 -04:00
Carsten Schafer
9dc6a6bf97 Update to ubuntu-latest for GH runner
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-04-24 15:30:49 -04:00
Ivan Chvets
1c0556f8bf fix: Version update - release 4.0.0
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-04-24 14:09:12 -04:00
i-chvets
d298139525 Merge pull request #403 from Telecominfraproject/wifi-14521_feat_use_clientcas_for_validation
WIFI-14521: feat: Added processing of clientcas
2025-04-09 11:50:04 -04:00
Ivan Chvets
a37c961f5b feat: Added processing of clientcas
https://telecominfraproject.atlassian.net/browse/WIFI-14521

Summary of changes:
- Updated code to add certificates from clientcas to trust chain and
  validate client certificates against it.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-04-09 10:30:52 -04:00
Nicolas Alfonso De Pineda Gutierrez
75bcbd748c Merge pull request #398 from Telecominfraproject/WIFI-14349-plat_cache.json-isnt-being-read-correctly-and-can-result-in-huge-memory-ussages-under-very-specific-situations
WIFI-14349-plat_cache.json-isnt-being-read-correctly-and-can-result-in-huge-memory-ussages-under-very-specific-situations
2025-01-21 16:00:14 +01:00
Nicolas de Pineda
b6eba2a96d fix: plat_cache.json not being read correctly
https://telecominfraproject.atlassian.net/browse/WIFI-14349

Summary of changes:
- Resolved an issue where a string field was being read as JSON, causing the output to be incorrectly surrounded by quotation marks.

Signed-off-by: Nicolas de Pineda <nicolas.depineda@galgus.ai>
2025-01-21 09:42:31 +01:00
17 changed files with 153 additions and 18 deletions

View File

@@ -21,7 +21,7 @@ defaults:
jobs:
docker:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral

View File

@@ -11,7 +11,7 @@ defaults:
jobs:
helm-package:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 3.2.1)
project(owgw VERSION 4.1.0)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

View File

@@ -880,6 +880,32 @@ The device should answer:
}
```
#### Controller wants the device to perform re-enrollment
Controller sends this command to trigger re-enrollment, i.e. update of operational certificate. Extreme care must be taken.
```json
{ "jsonrpc" : "2.0" ,
"method" : "reenroll" ,
"params" : {
"serial" : <serial number>,
"when" : Optional - <UTC time when to apply this config, 0 mean immediate, this is a suggestion>
},
"id" : <some number>
}
```
The device should answer:
```json
{ "jsonrpc" : "2.0" ,
"result" : {
"serial" : <serial number> ,
"status" : {
"error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
"txt" : <text describing the error or success>
},
"id" : <same number as request>
}
```
#### Controller wants the device to switch to another controller
Controller sends this when the device should change the controller it connects to without looking up a new redirector.

View File

@@ -213,6 +213,7 @@ namespace OpenWifi {
}
State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
State_.certificateIssuerName = PeerCert.issuerName();
poco_trace(Logger_,
fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,

View File

@@ -71,14 +71,18 @@ namespace OpenWifi {
bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate) {
if (IsCertOk()) {
if (!Certificate.issuedBy(*IssuerCert_)) {
poco_warning(
Logger(),
fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
return false;
// validate certificate agains trusted chain
for (const auto &cert : ClientCasCerts_) {
if (Certificate.issuedBy(cert)) {
return true;
}
}
return true;
poco_warning(
Logger(),
fmt::format(
"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA",
ConnectionId)
);
}
return false;
}
@@ -133,6 +137,13 @@ namespace OpenWifi {
Context->addChainCertificate(Issuing);
Context->addCertificateAuthority(Issuing);
// add certificates from clientcas to trust chain
ClientCasCerts_ = Poco::Net::X509Certificate::readPEM(Svr.ClientCas());
for (const auto &cert : ClientCasCerts_) {
Context->addChainCertificate(cert);
Context->addCertificateAuthority(cert);
}
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
Context->usePrivateKey(Key);
@@ -784,4 +795,4 @@ namespace OpenWifi {
return false;
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -223,6 +223,7 @@ namespace OpenWifi {
mutable std::array<std::mutex,MACHashMax> SerialNumbersMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
Poco::Net::SocketReactor Reactor_;

View File

@@ -111,7 +111,7 @@ namespace OpenWifi {
i >> cache;
for (const auto &[Type, Platform] : cache.items()) {
Platforms_[Type] = Poco::toLower(to_string(Platform));
Platforms_[Type] = Poco::toLower(Platform.get<std::string>());
}
} catch (...) {
}

View File

@@ -170,6 +170,7 @@ namespace OpenWifi {
{APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms},
{APCommands::Commands::fixedconfig, false, true, &RESTAPI_device_commandHandler::FixedConfig, 120000ms},
{APCommands::Commands::cablediagnostics, false, true, &RESTAPI_device_commandHandler::CableDiagnostics, 120000ms},
{APCommands::Commands::reenroll, false, true, &RESTAPI_device_commandHandler::ReEnroll, 120000ms},
};
@@ -1651,4 +1652,45 @@ namespace OpenWifi {
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
void RESTAPI_device_commandHandler::ReEnroll(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("REENROLL({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if(IsDeviceSimulated(SerialNumber_)) {
CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
GWObjects::ReEnroll PR;
if(!PR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.SubmittedBy = Requester();
Cmd.UUID = CMD_UUID;
Cmd.Command = uCentralProtocol::REENROLL;
std::ostringstream os;
ParsedBody_->stringify(os);
Cmd.Details = os.str();
Cmd.RunAt = PR.when;
Cmd.ErrorCode = 0;
Cmd.WaitingForFile = 0;
return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::reenroll, false, Cmd,
*ParsedBody_, *Request, *Response, timeout, nullptr, this,
Logger_);
}
} // namespace OpenWifi

View File

@@ -74,6 +74,8 @@ namespace OpenWifi {
const GWObjects::DeviceRestrictions &R);
void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void ReEnroll(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
static auto PathName() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

@@ -297,6 +297,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "certificateIssuerName", certificateIssuerName);
field_to_json(Obj, "connectReason", connectReason);
field_to_json(Obj, "uptime", uptime);
field_to_json(Obj, "compatible", Compatible);
@@ -358,6 +359,7 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "certificateIssuerName", certificateIssuerName);
field_from_json(Obj, "connectReason", connectReason);
field_from_json(Obj, "uptime", uptime);
field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
@@ -819,4 +821,14 @@ namespace OpenWifi::GWObjects {
}
return false;
}
bool ReEnroll::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serial", serialNumber);
field_from_json(Obj, "when", when);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
} // namespace OpenWifi::GWObjects

View File

@@ -42,6 +42,7 @@ namespace OpenWifi::GWObjects {
uint64_t sessionId = 0;
double connectionCompletionTime = 0.0;
std::uint64_t certificateExpiryDate = 0;
std::string certificateIssuerName;
std::uint64_t hasRADIUSSessions = 0;
bool hasGPS = false;
std::uint64_t sanity=0;
@@ -545,6 +546,12 @@ namespace OpenWifi::GWObjects {
std::uint64_t when;
std::vector<std::string> ports;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ReEnroll {
std::string serialNumber;
std::uint64_t when;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} // namespace OpenWifi::GWObjects

View File

@@ -625,6 +625,9 @@ static std::string DefaultAPSchema = R"foo(
],
"default": 80
},
"enable": {
"type": "boolean"
},
"require-mode": {
"description": "Stations that do no fulfill these HT modes will be rejected.",
"type": "string",
@@ -3952,8 +3955,10 @@ static std::string DefaultAPSchema = R"foo(
"inactive-deauth",
"key-mismatch",
"beacon-report",
"radar-detected"
]
"radar-detected",
"ft-finish",
"sta-authorized"
]
}
}
}
@@ -4956,6 +4961,9 @@ static std::string DefaultSWITCHSchema = R"foo(
],
"default": 80
},
"enable": {
"type": "boolean"
},
"require-mode": {
"type": "string",
"enum": [
@@ -7920,7 +7928,9 @@ static std::string DefaultSWITCHSchema = R"foo(
"inactive-deauth",
"key-mismatch",
"beacon-report",
"radar-detected"
"radar-detected",
"ft-finish",
"sta-authorized"
]
}
}

View File

@@ -68,6 +68,16 @@ namespace OpenWifi {
Context->addCertificateAuthority(Issuing);
}
if (!client_cas_.empty()) {
// add certificates specified in clientcas
std::vector<Poco::Crypto::X509Certificate> Certs =
Poco::Net::X509Certificate::readPEM(client_cas_);
for (const auto &cert : Certs) {
Context->addChainCertificate(cert);
Context->addCertificateAuthority(cert);
}
}
Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
Context->usePrivateKey(Key);

View File

@@ -45,6 +45,7 @@ namespace OpenWifi {
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
[[nodiscard]] inline auto ClientCas() const { return client_cas_; };
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
[[nodiscard]] inline auto Name() const { return name_; };

View File

@@ -583,6 +583,7 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char *FIXEDCONFIG = "fixedconfig";
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
static const char *REENROLL = "reenroll";
} // namespace OpenWifi::RESTAPI::Protocol
namespace OpenWifi::uCentralProtocol {
@@ -698,6 +699,8 @@ namespace OpenWifi::uCentralProtocol {
static const char *FIXEDCONFIG = "fixedconfig";
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
static const char *REENROLL = "reenroll";
} // namespace OpenWifi::uCentralProtocol
@@ -797,6 +800,7 @@ namespace OpenWifi::APCommands {
powercycle,
fixedconfig,
cablediagnostics,
reenroll,
unknown
};
@@ -812,7 +816,8 @@ namespace OpenWifi::APCommands {
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE,
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS,
RESTAPI::Protocol::REENROLL
};
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }

View File

@@ -14,6 +14,7 @@
#include "nlohmann/json.hpp"
#include "Poco/NObserver.h"
#include <Poco/Net/Context.h>
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/WebSocketImpl.h"
@@ -71,6 +72,7 @@ namespace OpenWifi {
const auto &RootCas =
MicroServiceConfigPath("ucentral.websocket.host.0.rootca", "");
const auto &Cas = MicroServiceConfigPath("ucentral.websocket.host.0.cas", "");
const auto &ClientCasFile = MicroServiceConfigPath("ucentral.websocket.host.0.clientcas", "");
Poco::Net::Context::Params P;
@@ -86,6 +88,7 @@ namespace OpenWifi {
Poco::Crypto::X509Certificate Cert(CertFileName);
Poco::Crypto::X509Certificate Root(RootCaFileName);
Poco::Crypto::X509Certificate Issuing(IssuerFileName);
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts;
Poco::Crypto::RSAKey Key("", KeyFileName, KeyPassword);
DeviceSecureContext->useCertificate(Cert);
@@ -93,7 +96,11 @@ namespace OpenWifi {
DeviceSecureContext->addCertificateAuthority(Root);
DeviceSecureContext->addChainCertificate(Issuing);
DeviceSecureContext->addCertificateAuthority(Issuing);
DeviceSecureContext->addCertificateAuthority(Root);
ClientCasCerts = Poco::Net::X509Certificate::readPEM(ClientCasFile);
for (const auto &cert : ClientCasCerts) {
DeviceSecureContext->addChainCertificate(cert);
DeviceSecureContext->addCertificateAuthority(cert);
}
DeviceSecureContext->enableSessionCache(true);
DeviceSecureContext->setSessionCacheSize(0);
DeviceSecureContext->setSessionTimeout(120);
@@ -1117,4 +1124,4 @@ namespace OpenWifi {
RTTYS_EndPoint::~RTTYS_EndPoint() {
}
} // namespace OpenWifi
} // namespace OpenWifi