Compare commits

...

25 Commits

Author SHA1 Message Date
John Crispin
56b5552928 cloud_discovery: use the correct certificte for CDS
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
1d94d298a0 certificates: add support for tar file based certificate storage
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
a9d1bd9940 est_client: fixup typo
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
39f31aaacf est_client: prevent downgrades to FW not supporting EST
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
f0f07705ea est_client: add reenroll support
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
5b655a5ca9 cloud_discovery: split EST code out into its own tool
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
f166bd64bd cloud_discovery: place intermediate files into the /tmp folder
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
9f5785203e cloud_discovery: rtrim() the extracted subject
this removes trailing \n\n characters

Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
0a958a0b3e ucentral-client: update to latest HEAD
4d01f3e use new operational cert and ca

Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
4d42a01c8b luci-mod-ucentral: update certupdate for insta birth certificates
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
45065a6da1 certificates: do not check for cas.pem when mounting certs
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
410f20561c certificates: set new certs inside UCI
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
ce104115f7 ucentral-schema: update examples to use new certs
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
d7e0a8ad6b ucentral-client: only start the service if the operational cert is present
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
c4a12b0ea3 cloud_discovery: add insta EST support
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
9871137a9d cloud_discovery: add initial ubus status call
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
8837213129 ucentral-client: add support for hostname_validation
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
f0dbbad723 cloud_discovery: add support for hostname_validation
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
dddba2986f ucentral-client: update to latest HEAD
769cf61 make hostname validation optional

Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
fafe81306d luci-mod-ucentral: remove digicert specific files
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
f2cb4789eb cloud_discovery: depend on the certificates package
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
3e08248e8c cloud_discovery: add option 138 support
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
a6ba2436af netifd: drop dhcp option 138 patch
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
a4af406f49 cloud_discovery: remove pki2 env lookup
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
John Crispin
f0929dc1b3 firstcontact: remove now unused digicert client
Fixes: WIFI-14694
Signed-off-by: John Crispin <john@phrozen.org>
2025-06-27 07:41:05 +02:00
24 changed files with 346 additions and 386 deletions

View File

@@ -5,12 +5,10 @@ START=09
copy_certificates() {
[ -f /certificates/key.pem ] || return
cp /certificates/*.pem /etc/ucentral/
chown root.network /etc/ucentral/*.pem
chmod 0440 root.network /etc/ucentral/*.pem
cp /certificates/cert.pem /certificates/key.pem /certificates/operational.* /etc/ucentral/
chown root.network /etc/ucentral/*.pem /etc/ucentral/*.ca
chmod 0440 root.network /etc/ucentral/*.pem /etc/ucentral/*.ca
[ -f /certificates/gateway.json ] && cp /certificates/gateway.json /etc/ucentral/gateway.flash
[ -f /certificates/dev-id ] && cp /certificates/dev-id /etc/ucentral/
[ -f /etc/ucentral/dev-id ] && chmod 0400 /etc/ucentral/dev-id
[ -f /certificates/restrictions.json ] && cp /certificates/restrictions.json /etc/ucentral/
[ -f /certificates/sign_pubkey.pem ] && cp /certificates/sign_pubkey.pem /etc/ucentral/
country=`cat /certificates/ucentral.defaults | jsonfilter -e '@.country'`

View File

@@ -2,5 +2,5 @@
uci add system certificates
uci set system.@certificates[-1].key=/etc/ucentral/key.pem
uci set system.@certificates[-1].cert=/etc/ucentral/cert.pem
uci set system.@certificates[-1].ca=/etc/ucentral/cas.pem
uci set system.@certificates[-1].cert=/etc/ucentral/operational.pem
uci set system.@certificates[-1].ca=/etc/ucentral/operational.ca

View File

@@ -1,25 +1,22 @@
#!/bin/sh
check_certificates() {
[ -f /certificates/cas.pem -a -f /certificates/cert.pem -a -f /certificates/key.pem ] && exit 0
[ -f /certificates/cert.pem -a -f /certificates/key.pem ] && exit 0
}
check_certificates
bootconfig_lookup() {
case "$(fw_printenv -n cert_part)" in
0) echo "0:BOOTCONFIG"
;;
1) echo "0:BOOTCONFIG1"
;;
esac
}
. /lib/functions.sh
mkdir -p /certificates /etc/ucentral/
mtd=$(find_mtd_index certificates)
if [ "$(head -c 4 /dev/mtd$mtd)" == "hsqs" ]; then
mount -t squashfs /dev/mtdblock$mtd /certificates
else
[ -n "$mtd" -a -f /sys/class/mtd/mtd$mtd/oobsize ] && ubiattach -p /dev/mtd$mtd
if [ -n "$(ubinfo -a | grep certificates)" ]; then
[ -e /dev/ubi0 ] && mount -t ubifs ubi0:certificates /certificates
[ -e /dev/ubi1 ] && mount -t ubifs ubi1:certificates /certificates
fi
fi
case "$(board_name)" in
cig,wf660a)
mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//')
@@ -31,8 +28,28 @@ cig,wf672)
;;
sonicfi,rap7110c-341x)
mmc_dev=$(echo $(find_mmc_part "certificates") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /certificates
[ -n "$mmc_dev" ] && mount -t squashfs /dev/$mmc_dev /mnt
bootconfig=$(bootconfig_lookup)
if [ -n "$bootconfig" ]; then
mmc_dev=$(echo $(find_mmc_part "$bootconfig") | sed 's/^.\{5\}//')
[ -n "$mmc_dev" ] && tar xf /dev/$mmc_dev -C /certificates
else
cp /mnt/* /certificates/
umount /mnt
fi
;;
*)
mtd=$(find_mtd_index certificates)
if [ "$(head -c 4 /dev/mtd$mtd)" == "hsqs" ]; then
mount -t squashfs /dev/mtdblock$mtd /certificates
else
[ -n "$mtd" -a -f /sys/class/mtd/mtd$mtd/oobsize ] && ubiattach -p /dev/mtd$mtd
if [ -n "$(ubinfo -a | grep certificates)" ]; then
[ -e /dev/ubi0 ] && mount -t ubifs ubi0:certificates /certificates
[ -e /dev/ubi1 ] && mount -t ubifs ubi1:certificates /certificates
fi
fi
esac
check_certificates

View File

@@ -0,0 +1,25 @@
#!/bin/sh
bootconfig_lookup() {
bootconfig="$(fw_printenv -n cert_part)"
case "$(fw_printenv -n cert_part)" in
0) echo "0:BOOTCONFIG1"
bootconfig=1
;;
*) echo "0:BOOTCONFIG"
bootconfig=0
;;
esac
fw_setenv cert_part $bootconfig
}
. /lib/functions.sh
case "$(board_name)" in
sonicfi,rap7110c-341x)
cd /certificates
tar cf /tmp/certs.tar
bootconfig=$(bootconfig_lookup)
mmc_dev=$(echo $(find_mmc_part $bootconfig) | sed 's/^.\{5\}//')
dd if=/tmp/certs.tar of=/dev/$bootconfig
;;
esac

View File

@@ -12,6 +12,7 @@ define Package/cloud_discovery
SECTION:=ucentral
CATEGORY:=uCentral
TITLE:=TIP cloud_discovery
DEPENDS:=+certificates
endef
Build/Compile=

View File

@@ -22,13 +22,6 @@ start_service() {
[ "$valid" == "true" ] ||
/usr/share/ucentral/ucentral.uc /etc/ucentral/ucentral.cfg.0000000001 > /dev/null
[ "$(fw_printenv -n pki2)" -eq 1 ] || {
/etc/init.d/cloud_discover disable
return
}
/etc/init.d/firstcontact disable
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn

View File

@@ -80,7 +80,7 @@ function gateway_write(data) {
gateway ??= {};
let new = {};
let changed = false;
for (let key in [ 'server', 'port', 'valid' ]) {
for (let key in [ 'server', 'port', 'valid', 'hostname_validate' ]) {
if (exists(data, key))
new[key] = data[key];
else if (exists(gateway, key))
@@ -144,7 +144,7 @@ function set_state(set) {
function discover_dhcp() {
let dhcp = readjsonfile('/tmp/cloud.json');
if (dhcp?.dhcp_server && dhcp?.dhcp_port) {
if (gateway_write({ server: dhcp.dhcp_server, port:dhcp.dhcp_port, valid: false })) {
if (gateway_write({ server: dhcp.dhcp_server, port:dhcp.dhcp_port, valid: false, hostname_validate: dhcp.no_validation ? 0 : 1 })) {
ulog(LOG_INFO, `Discovered cloud via DHCP ${dhcp.dhcp_server}:${dhcp.dhcp_port}\n`);
client_start();
set_state(VALIDATING);
@@ -160,27 +160,30 @@ function redirector_lookup() {
let serial = uci.get('system', '@system[-1]', 'mac');
fs.unlink(path);
system(`curl -k --cert /etc/ucentral/cert.pem --key /etc/ucentral/key.pem --cacert /etc/ucentral/cas.pem https://openlan.keys.tip.build/v1/devices/${serial} --output /tmp/ucentral.redirector`);
system(`curl -k --cert /etc/ucentral/operational.pem --key /etc/ucentral/key.pem --cacert /etc/ucentral/operational.ca https://openlan.keys.tip.build/v1/devices/${serial} --output /tmp/ucentral.redirector`);
if (!fs.stat(path))
return;
let redir = readjsonfile(path);
if (redir?.controller_endpoint) {
let controller_endpoint = split(redir.controller_endpoint, ':');
if (gateway_write({ server: controller_endpoint[0], port: controller_endpoint[1] || 15002, valid: false })) {
ulog(LOG_INFO, `Discovered cloud via lookup service ${redir.server}:${redir.port}\n`);
if (gateway_write({ server: controller_endpoint[0], port: controller_endpoint[1] || 15002, valid: false, hostname_validate: 1 })) {
ulog(LOG_INFO, `Discovered cloud via lookup service ${controller_endpoint[0]}:${controller_endpoint[1] || 15002}\n`);
client_start();
set_state(VALIDATING);
}
} else {
ulog(LOG_INFO, 'Failed to discover cloud endpoint\n');
}
}
function discover_flash() {
if (!fs.stat('/etc/ucentral/gateway.flash'))
return false;
return 1;
ulog(LOG_INFO, 'Using pre-populated cloud information\n');
fs.writefile('/etc/ucentral/gateway.json', fs.readfile('/etc/ucentral/gateway.flash'));
client_start();
set_state(VALIDATING);
return 0;
}
function time_is_valid() {
@@ -210,7 +213,10 @@ function interval_handler() {
if (discover_dhcp())
return;
if (discover_flash())
if (system('/usr/bin/est_client enroll'))
return;
if (!discover_flash())
return;
redirector_lookup();
@@ -287,6 +293,25 @@ let ubus_methods = {
}
},
status: {
call: function(req) {
const names = [ 'discover', 'validate', 'online', 'offline', 'orphan' ];
let ret = { state: names[state] };
switch(state){
case OFFLINE:
ret.since = time() - offline_time;
break;
case ORPHAN:
ret.since = time() - orphan_time;
break;
case VALIDATING:
ret.since = time() - validate_time;;
break;
}
return ret;
},
args: {},
},
};
if (gateway_available()) {

View File

@@ -0,0 +1,172 @@
#!/usr/bin/ucode
'use strict';
import { ulog_open, ulog, ULOG_SYSLOG, ULOG_STDIO, LOG_DAEMON, LOG_INFO } from 'log';
import * as fs from 'fs';
ulog_open(ULOG_SYSLOG | ULOG_STDIO, LOG_DAEMON, "est_client");
function generate_csr(cert) {
if (!fs.stat('/tmp/csr.nohdr.p10')) {
let pipe = fs.popen(`openssl x509 -in ${cert} -noout -subject`);
let subject = pipe.read("all");
pipe.close();
subject = rtrim(subject);
subject = replace(subject, 'subject=', '/');
subject = replace(subject, ' = ', '=');
subject = replace(subject, ', ', '/');
let ret = system(`openssl req -subj "${subject}" -new -key /etc/ucentral/key.pem -out /tmp/csr.p10`);
if (ret) {
ulog(LOG_INFO, 'Failed to generate CSR\n');
return 1;
}
let input = fs.open('/tmp/csr.p10', 'r');
let output = fs.open('/tmp/csr.nohdr.p10', 'w');
let line;
while (line = input.read('line')) {
if (substr(line, 0, 4) == '----')
continue;
output.write(line);
}
input.close();
output.close();
ulog(LOG_INFO, 'Generated CSR\n');
}
return 0;
}
function store_operational_cert(path, target) {
system('mount_certs');
system(`cp ${path} /certificates/${target}`);
system('store_certs');
ulog(LOG_INFO, `Persistently stored ${target}\n`);
}
function p7_too_pem(src, dst) {
let input = fs.readfile(src);
let output = fs.open('/tmp/convert.p7', 'w');
output.write('-----BEGIN PKCS #7 SIGNED DATA-----\n');
output.write(`${input}\n-----END PKCS #7 SIGNED DATA-----`);
output.close();
let ret = system(`openssl pkcs7 -outform PEM -print_certs -in /tmp/convert.p7 -out ${dst}`);
if (ret) {
ulog(LOG_INFO, 'Failed to convert P7 to PEM\n');
return 1;
}
ulog(LOG_INFO, 'Converted P7 to PEM\n');
return 0;
}
function call_est_server(cert, target) {
if (generate_csr(cert))
return 1;
let ret = system('curl -X POST https://qaest.certificates.open-lan.org:8001/.well-known/est/simpleenroll -d @/tmp/csr.nohdr.p10 -H "Content-Type: application/pkcs10" --cert /etc/ucentral/cert.pem --key /etc/ucentral/key.pem --cacert /etc/ucentral/insta.pem -o /tmp/operational.nohdr.p7');
if (ret) {
ulog(LOG_INFO, 'Failed to request operational certificate\n');
return 1;
}
ulog(LOG_INFO, 'EST succeeded\n');
return p7_too_pem('/tmp/operational.nohdr.p7', target);
}
function simpleenroll() {
if (fs.stat('/etc/ucentral/operational.pem')) {
ulog(LOG_INFO, 'Operational certificate is present\n');
return 0;
}
if (call_est_server('/etc/ucentral/cert.pem', '/etc/ucentral/operational.pem'))
return 1;
ulog(LOG_INFO, 'Operational cert acquired\n');
store_operational_cert('/etc/ucentral/operational.pem', 'operational.pem');
return 0;
}
function simplereenroll() {
if (!fs.stat('/etc/ucentral/operational.pem')) {
ulog(LOG_INFO, 'Operational certificate was not found\n');
return 0;
}
if (call_est_server('/etc/ucentral/operational.pem', '/tmp/operational.pem'))
return 1;
ulog(LOG_INFO, 'Operational cert updated\n');
store_operational_cert('/tmp/operational.pem', 'operational.pem');
return 0;
}
function load_operational_ca() {
if (fs.stat('/etc/ucentral/operational.ca')) {
ulog(LOG_INFO, 'Operational CA is present\n');
return 0;
}
let ret = system('curl -X GET https://qaest.certificates.open-lan.org:8001/.well-known/est/cacerts --cert /etc/ucentral/cert.pem --key /etc/ucentral/key.pem --cacert /etc/ucentral/insta.pem -o /tmp/operational.ca.nohdr.p7');
if (!ret)
ret = p7_too_pem('/tmp/operational.ca.nohdr.p7', '/etc/ucentral/operational.ca');
if (ret) {
ulog(LOG_INFO, 'Failed to load CA\n');
return 1;
}
system('cat /etc/ucentral/openlan.pem >> /etc/ucentral/operational.ca');
ulog(LOG_INFO, 'Acquired CA\n');
store_operational_cert('/etc/ucentral/operational.ca', 'operational.ca');
return 0;
}
function fwtool() {
let pipe = fs.popen(`openssl x509 -in /etc/ucentral/cert.pem -noout -issuer`);
let issuer = pipe.read("all");
pipe.close();
if (!(match(issuer, /OpenLAN/) && match(issuer, /Birth CA/)))
return 0;
ulog(LOG_INFO, 'The issuer is insta\n');
let metadata = fs.readfile('/tmp/sysupgrade.meta');
if (metadata)
metadata = json(metadata);
if (!metadata)
return 0;
if (!metadata.est_supported) {
ulog(LOG_INFO, 'The image does not support EST\n');
return 1;
}
ulog(LOG_INFO, 'The image supports EST\n');
return 0;
}
switch(ARGV[0]) {
case 'enroll':
if (simpleenroll())
exit(1);
if (load_operational_ca())
exit(1);
exit(0);
case 'reenroll':
if (simplereenroll())
exit(1);
exit(0);
case 'fwtool':
exit(fwtool());
}

View File

@@ -5,6 +5,7 @@ import * as fs from 'fs';
let cmd = ARGV[0];
let ifname = getenv("interface");
let opt224 = getenv("opt138");
let opt224 = getenv("opt224");
if (cmd != 'bound' && cmd != 'renew')
@@ -21,6 +22,13 @@ if (file.server && file.port && file.valid)
let cloud = {
lease: true,
};
if (opt138) {
let dhcp = hexdec(opt138);
dhcp = split(dhcp, ':');
cloud.dhcp_server = dhcp[0];
cloud.dhcp_port = dhcp[1] ?? 15002;
cloud.no_validation = true;
}
if (opt224) {
let dhcp = hexdec(opt224);
dhcp = split(dhcp, ':');
@@ -29,7 +37,7 @@ if (opt224) {
}
fs.writefile('/tmp/cloud.json', cloud);
if (opt224 && cmd == 'renew') {
if ((opt138 || opt224) && cmd == 'renew') {
let ubus = libubus.connect();
ubus.call('cloud', 'renew');
}

View File

@@ -1,25 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=firstcontact
PKG_RELEASE:=1
PKG_LICENSE:=BSD-3-Clause
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/firstcontact
SECTION:=ucentral
CATEGORY:=uCentral
TITLE:=TIP DigiCert firstcontact
DEPENDS:=+libubox +libcurl +libopenssl +certificates
endef
define Package/firstcontact/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/digicert $(1)/usr/sbin/
$(CP) ./files/* $(1)
endef
$(eval $(call BuildPackage,firstcontact))

View File

@@ -1,12 +0,0 @@
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
PROG=/usr/bin/ucode
start_service() {
procd_open_instance
procd_set_param command "$PROG" -l uci -l fs /usr/share/ucentral/firstcontact.uc
procd_set_param respawn 1 10 0
procd_close_instance
}

View File

@@ -1,3 +0,0 @@
#!/bin/sh
[ -f "/etc/ucentral/gateway.json" ] && /etc/init.d/firstcontact disable
[ -f "/etc/ucentral/gateway.json" ] || /etc/init.d/ucentral disable

View File

@@ -1,83 +0,0 @@
let config = {};
function store_config() {
let redir = split(config.Redirector, ":");
let gw = {
server: redir[0],
port: redir[1] || 15002
};
fs.writefile('/etc/ucentral/gateway.json', gw);
}
function store_config_uci(path) {
let cursor = uci.cursor(path);
let redir = split(config.Redirector, ":");
cursor.load("ucentral");
cursor.set("ucentral", "config", "server", redir[0]);
cursor.set("ucentral", "config", "port", redir[1] || 15002);
cursor.commit();
}
function digicert() {
let devid;
let fd = fs.open("/etc/ucentral/dev-id", "r");
if (!fd) {
warn("firstcontact: failed to find device id");
exit(1);
}
devid = fd.read("all");
fd.close();
ret = system(sprintf('/usr/sbin/digicert -i %s', devid));
if (ret) {
warn("firstcontact failed to contact redirector, check DHCP option\n");
let fd = fs.open("/tmp/capwap/dhcp_opt.txt", "r");
if (!fd) {
warn("No redirector found\n");
exit(1);
} else {
config.Redirector = fd.read("all");
fd.close();
}
} else {
let redirector = { };
let fd = fs.open("/etc/ucentral/redirector.json", "r");
if (fd) {
let data = fd.read("all");
fd.close();
try {
redirector = json(data);
}
catch (e) {
warn("firstcontact: Unable to parse JSON data in %s: %s", path, e);
exit(1);
}
}
for (let r in redirector.fields)
if (r.name && r.value)
config[r.name] = r.value;
if (!config.Redirector) {
warn("Reply is missing Redirector field\n");
exit(1);
}
}
}
if (!fs.stat('/etc/ucentral/gateway.json')) {
digicert();
store_config();
store_config_uci();
store_config_uci("/etc/config-shadow/");
warn("firstcontact: managed to look up redirector\n");
}
system("/etc/init.d/ucentral enable");
system("/etc/init.d/firstcontact disable");
system("reload_config");
system("/etc/init.d/ucentral start");
system("/etc/init.d/firstcontact stop");

View File

@@ -1,13 +0,0 @@
cmake_minimum_required(VERSION 2.6)
PROJECT(digicert C)
INCLUDE(GNUInstallDirs)
ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
ADD_EXECUTABLE(digicert digicert.c)
TARGET_LINK_LIBRARIES(digicert curl crypto ssl ubox)
INSTALL(TARGETS digicert
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
)

View File

@@ -1,104 +0,0 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <curl/curl.h>
#include <libubox/ulog.h>
static const char *file_cert = "/etc/ucentral/cert.pem";
static const char *file_key = "/etc/ucentral/key.pem";
static const char *file_json = "/etc/ucentral/redirector.json";
static const char *file_dbg = "/tmp/digicert.hdr";
int main(int argc, char **argv)
{
FILE *fp_json;
FILE *fp_dbg;
CURLcode res;
CURL *curl;
char *devid = NULL;
char *url;
alarm(15);
while (1) {
int option = getopt(argc, argv, "k:c:o:hi:");
if (option == -1)
break;
switch (option) {
case 'k':
file_key = optarg;
break;
case 'c':
file_cert = optarg;
break;
case 'o':
file_json = optarg;
break;
case 'i':
devid = optarg;
break;
default:
case 'h':
printf("Usage: digicert OPTIONS\n"
" -k <keyfile>\n"
" -c <certfile>\n"
" -o <outfile>\n"
" -i <devid>\n");
return -1;
}
}
if (!devid) {
fprintf(stderr, "missing devid\n");
return -1;
}
ulog_open(ULOG_SYSLOG | ULOG_STDIO, LOG_DAEMON, "digicert");
ULOG_INFO("attempting first contact\n");
fp_dbg = fopen(file_dbg, "wb");
fp_json = fopen(file_json, "wb");
if (!fp_json) {
ULOG_ERR("failed to create %s\n", file_json);
return -1;
}
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (!curl) {
ULOG_ERR("curl_easy_init failed\n");
return -1;
}
if (asprintf(&url, "https://clientauth.one.digicert.com/iot/api/v2/device/%s", devid) < 0) {
ULOG_ERR("failed to assemble url\n");
return -1;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp_json);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp_dbg);
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLCERT, file_cert);
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
curl_easy_setopt(curl, CURLOPT_SSLKEY, file_key);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
ULOG_ERR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
else
ULOG_INFO("downloaded first contact data\n");
curl_easy_cleanup(curl);
curl_global_cleanup();
ulog_close();
return (res != CURLE_OK);
}

View File

@@ -17,14 +17,16 @@ mkdir -p /tmp/certs
tar x -C /tmp/certs -f /tmp/certs.tar
# make sure the required files exist
[ -f /tmp/certs/cas.pem -a -f /tmp/certs/key.pem -a -f /tmp/certs/cert.pem ] || exit 1
[ -f /tmp/certs/gateway.json -o -f /tmp/certs/dev-id ] || exit 1
[ -f /tmp/certs/key.pem -a -f /tmp/certs/cert.pem ] || exit 1
# copy the certificates to /etc
cp /tmp/certs/*.pem /certificates
# remove old operational certs
rm /certificates/operational.*
# copy dev-id or gateway.json
for a in dev-id gateway.json; do
for a in gateway.json; do
if [ -f /tmp/certs/$a ]; then
cp /tmp/certs/$a /certificates
else

View File

@@ -0,0 +1,6 @@
-----BEGIN CERTIFICATE-----
MIIFajCCA1KgAwIBAgICDnowDQYJKoZIhvcNAQELBQAwHzEdMBsGA1UEAwwUT3BlbkxBTiBEZW1vIFJvb3QgQ0EwHhcNMjUwMjIxMTUwMDAwWhcNMjYwMjIxMTUwMDAwWjAgMR4wHAYDVQQDExVPcGVuTEFOIERlbW8gQmlydGggQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVWIyySul6Fv4wl1O+DQpaLRa0p+Az5L/jcqTpdVf6w+8tlmeIY9C28uDQoDjewrIkvf3lcfK86nshs02s9ehqZUnEP8+GvKM19x3JbWxeTvWwFirjHir4x897iQ606bAMbrHHtntI9ZyBZyXDGeElGJxJQNX+0d50SFq609cB3yxpBPJ67ag+4Oq0uHgROHjEQMrfwLwlAune0c1fjQDrN14PDNjMZHvvhc/pkAHxR1PP6LOFNV5NuQ58tC5N7R2EqqFbIJ8VZgcagrGRYuAuFFTaV+D7RIt9xGTuWlCyxHI7VkRBJ1mRoEr4GOrP9QFjBD8NzNK+/wnR/fZwhpEnRsgHiI33wKHBDg+l3r8tvRzuB5X6Gl/SfuAeaoCuDHMncTjQg1zGhyEwjQhUe4RY3w+yHAjeeOE6c5spOMDDdaBibkzLmSjXztuLeAdzsUcD3fvGeOvh9vG14TKEmF8puNkqEcc0W8NyUWKFdr9umdJEMbaRSSsMGtp8bDj3Ddh4PhEJrIFeo89+HwXhU6sk+wzE9BULTohahsfwOV/08t1cZ3Q04Oj1KI+4YWu8BJns5gX35rQ8GIbkXQwfvFMwqmbg+ij2o9HWdkSL4bcqW/83Ho+31ce210rVGPK9cav0CjA2Eexgxi45cbgnfoade74Qa5zXboJEBmp7rbo4swIDAQABo4GuMIGrMB8GA1UdIwQYMBaAFDzIg8eyTI3xc4A2R60f8HanhBZDMB0GA1UdDgQWBBS5xC3inqLQl+vxzn9PsjNzlZ5hYDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vZGVtby5jZXJ0aWZpY2F0ZS5maS9jcmwvT3BlbkxBTkRlbW9Sb290Q0EuY3JsMA0GCSqGSIb3DQEBCwUAA4ICAQA9DJEjsDLqtSFkF0XTWfzbebXA+X8++Qmiukrw0s2LRx798ce0mVITRAFDLf78BeUYF0B+PQ8hgq4fWyFsXRgZVrITd1BszT3LJ2r/6xWQJVpVHzLqKgIlW/PY/uTUz+xqR0Ev6hYrmrjfya0K0XEZZqxkmrTrcECaA3RCFkWQl9ZUlb9BClmdhayO8x1XpJplIYAMKVuoPL9IUQH6HUPFnzlPNQHIK9gcFACtgPVWCJg3IAvSLa41KpRxTDwGFvlrNKtkBlGRYhFGCHWXXZn8fdQHW9vykkkfPOaPR/AVyuRzfAT6wbtVWSy38BurSdqSCuNQPQBfF2vMeUGwNbD/7B4tYrWVtnIbgxRPKvX0o3mZkKry6BJf2m/AKWA16W+i4ojnPRORLTTq9cEZ0WL6NRHCgMrbWaCs/+ADTErqK6cv7GhoOVEiqugvnz93dit2IXg4zdDJ4hF9ZSlicwgZKVvMqnNQ1iiXezIQBehgYcWwXRIfdrRPe88HgkySuDZ2lkKYdc+oTc6e7upRh4Kh2ZSipcRb6ehPan533jnQJyU8A9vFAJiQfZZ4lD3tcsqlsDnlu5YEDYSjcfnkyOH/Mlx5VVTWYGvqNNVKRDw2slSxKwVCobkcF/2dAxP9DqOaGaCnMeOaR7kMaBm5d1fwb+bCl9usQAELjZBv2vAH8g==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFIDCCAwigAwIBAgICDnkwDQYJKoZIhvcNAQELBQAwHzEdMBsGA1UEAwwUT3BlbkxBTiBEZW1vIFJvb3QgQ0EwHhcNMjUwMjIxMTUwMDAwWhcNMjYwMjIxMTUwMDAwWjAfMR0wGwYDVQQDDBRPcGVuTEFOIERlbW8gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMjExylKdJWoJu9mOHPJ6yZFXKe1lE467G65acpS2FKIWnPVFjNCmATMpkMOIFzEFwyFdbQjzOidtiL+73zlE52lOJpXCfOcxDFqDYDJJ8//J1/gQWsBaKpSvgLiHU/0awkQg+yJYZpj8YZa4NkFe+zTjQScSfOsqPPb3rZ7DOQ2BKAhjVShKmVbtNil0iO0zm8vE8DNkktTNMREp2pzb8MbCAgfOkwlrby6T+rV3TvmjThGdFUb5lWDFxWtlF8W0SUII9qj7p5TdGpryeLsO0nZTBtS4HxZNdvmKOHfgcRHmSZIJigB2NzKLNrXF9JBW0WnUSwZJZAG2C1RTx6lADILPueuusyfR/hZ3koKi4PHnSiTwQghzia9K9QjNHq5z9R9ZoCnhBg1VyU4LKmp862L0sIp2vgnOYunEIi9aCYBaDwo+0FuVjZuXyDIatwVuA7TN5IWPHA6XLdOt1mmkeYy1Ldr4XHjdondhtOyeei1UFXmyyLm2+kmRYfTm91TqYmNzRgbRV2NHO50AmsnBknX4Rv3gishGe0+dV5yFcUwZud0z2rSCkuoai5tKrPT+6Y6NqkT9u9HFifIBXnLwEzVUqHRtW6SuWj2DClVQIXIUZtFnhY4GuTuf6DlzgnXO58oDVCZmCW4ULIpbqGeRsvBHR8Sw5JXP/1+TMUYhE8TAgMBAAGjZjBkMB8GA1UdIwQYMBaAFDzIg8eyTI3xc4A2R60f8HanhBZDMB0GA1UdDgQWBBQ8yIPHskyN8XOANketH/B2p4QWQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAgEAkHZ5KR8IOrdfMFy+iOvauvZxfQ84LL6TpB2FQKDjneJUdd7c29UJJFNW/0mp4Gc6jKZab6J8Dx/pNnbH0RqFjGjeRGtJ4Sk0G7gf9zw1S7qut5WJDcisM9l/wXC+zy/KSKKPQmbt0grWOtU7+NNPh1YU76hIrInq/u2sVZyKH8SXQ957fbJk6BX6JTKyNEn05AB6rNSrbOWo8sy2MlcJ7bBsrWYI1t6GcWFh4b36bLu7/dKJWpyFNXXIkKJsgMEDpEQae56+fSSDo0KRNtYB82fNZDIQlGK81rGJWNzAahM+3GD1tgk/3ZVugfaJhcBpoHHKNOGqZAvtirLAIDocno7AzqoeIz974Rh2Olsl2/arApYPyyfi8PMYuFe/d4h+Wie8n+jh5n48lZ2Ve4PK+j+QHD6tTZS4f0bGnPL1puMxzQloltuQWgLDeVfEgrc3snLvjOg8aDzWm/es85lP8XcyW54U4t3JmrNUC2C7v+Uafx7cL7eDeunhs+BRhtGV+IUmjub2IrpqZp3zZqn+LVRdYJIy/qHhjS5+ImckXkFojOmeWhfmEmYSuNP8Oa6cGuXp829qnbxLh9Qzi3TfXV883KLse4kL5Zl7gBA/4hz2hVMyGJ8fY+VvzbaTuOXyvKJ+rGZCTcRSeotBLnIevVMiL7SqOEwN0j4Mfbznfq8=
-----END CERTIFICATE-----

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-client
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-client.git
PKG_MIRROR_HASH:=20d0573e5460ae9780307ab9d54234bb75d3b98fb36806f896819918087b14df
PKG_MIRROR_HASH:=c266b7126cb1388da83c3f35613ed4821046a021e36880b37be38976a81dac9b
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2024-10-20
PKG_SOURCE_VERSION:=8c45f965c30d1cf11e3a5a625a5e2baf3178697f
PKG_SOURCE_VERSION:=4d01f3ee74cd08cb894f372c8cc185d299f977a7
PKG_LICENSE:=BSD-3-Clause
PKG_MAINTAINER:=John Crispin <john@phrozen.org>

View File

@@ -14,6 +14,7 @@ reload_service() {
}
start_service() {
[ -f /etc/ucentral/operational.ca -a -f /etc/ucentral/operational.pem ] || return
[ -s /etc/ucentral/capabilities.json ] || rm /etc/ucentral/capabilities.json
[ -f /etc/ucentral/capabilities.json ] || /usr/share/ucentral/capabilities.uc
@@ -44,6 +45,7 @@ start_service() {
server=$(cat /etc/ucentral/gateway.json | jsonfilter -e '@["server"]')
port=$(cat /etc/ucentral/gateway.json | jsonfilter -e '@["port"]')
hostname_validate=$(cat /etc/ucentral/gateway.json | jsonfilter -e '@["hostname_validate"]')
boot_cause=$(cat /tmp/pstore | jsonfilter -e '@["pstore"][-1]'.boot_cause)
[ -z $boot_cause ] && boot_cause=coldboot
@@ -52,6 +54,7 @@ start_service() {
[ -n "$serial" ] && procd_append_param command -S $serial
[ -n "$server" ] && procd_append_param command -s $server
[ -n "$port" ] && procd_append_param command -P $port
[ "$hostname_validate" -eq 0 ] || procd_append_param command -h
[ "$debug" -eq 0 ] || procd_append_param command -d
[ "$insecure" -eq 0 ] || procd_append_param command -i
[ -z "$(mount | grep 'tmpfs on / type tmpfs')" ] || procd_append_param command -r

View File

@@ -37,8 +37,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {
@@ -64,8 +64,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {
@@ -91,8 +91,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {
@@ -118,8 +118,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {
@@ -145,8 +145,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {

View File

@@ -37,8 +37,8 @@
"ieee80211w": "optional"
},
"certificates": {
"ca-certificate": "/etc/ucentral/cas.pem",
"certificate": "/etc/ucentral/cert.pem",
"ca-certificate": "/etc/ucentral/operational.ca",
"certificate": "/etc/ucentral/operational.pem",
"private-key": "/etc/ucentral/key.pem"
},
"radius": {

View File

@@ -1,93 +0,0 @@
From e4ad9777fae3bb3a71988fa738f16cb8d6884d7e Mon Sep 17 00:00:00 2001
From: Tanya Singh <tanya_singh@accton.com>
Date: Tue, 28 Jun 2022 17:11:52 +0800
Subject: [PATCH 29/68] netifd: Support DHCP option 138 and store values in
/tmp/capwap/dhcp_opt.txt
Signed-off-by: Tanya Singh <tanya_singh@accton.com>
---
.../netifd/files/lib/netifd/dhcp.script | 22 +++++++++++++++++++
.../netifd/files/lib/netifd/proto/dhcp.sh | 1 +
.../busybox/patches/531-dhcp_opt_capwap.patch | 18 +++++++++++++++
3 files changed, 41 insertions(+)
create mode 100644 package/utils/busybox/patches/531-dhcp_opt_capwap.patch
diff --git a/package/network/config/netifd/files/lib/netifd/dhcp.script b/package/network/config/netifd/files/lib/netifd/dhcp.script
index 6fcf139beb..29de85f221 100755
--- a/package/network/config/netifd/files/lib/netifd/dhcp.script
+++ b/package/network/config/netifd/files/lib/netifd/dhcp.script
@@ -4,6 +4,24 @@
. /lib/functions.sh
. /lib/netifd/netifd-proto.sh
+WORKING_PATH=/tmp/capwap
+DHCP_OPT_FILE=${WORKING_PATH}/dhcp_opt.txt
+DHCP_OPT_FILE_TMP=${WORKING_PATH}/dhcp_opt_tmp.txt
+
+set_capwap_ip()
+{
+ local ip
+ if [ ! -d "${WORKING_PATH}" ]; then
+ mkdir -p ${WORKING_PATH}
+ fi
+ for ip in ${capwap}; do
+ echo -n ${ip} >> ${DHCP_OPT_FILE_TMP}
+ done
+ if ! cmp -s "${DHCP_OPT_FILE}" "${DHCP_OPT_FILE_TMP}"; then
+ mv ${DHCP_OPT_FILE_TMP} ${DHCP_OPT_FILE}
+ fi
+}
+
set_classless_routes() {
local max=128
while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do
@@ -111,6 +129,10 @@ case "$1" in
;;
esac
+if [ -n "${capwap}" ]; then
+ set_capwap_ip
+fi
+
# user rules
[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user "$@"
for f in /etc/udhcpc.user.d/*; do
diff --git a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
index 636b4654ff..18a9aaf2a3 100755
--- a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
+++ b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
@@ -61,6 +61,7 @@ proto_dhcp_setup() {
[ "$delegate" = "0" ] && proto_export "IFACE6RD_DELEGATE=0"
# Request classless route option (see RFC 3442) by default
[ "$classlessroute" = "0" ] || append dhcpopts "-O 121"
+ append dhcpopts "-O 138"
proto_export "INTERFACE=$config"
proto_run_command "$config" udhcpc \
diff --git a/package/utils/busybox/patches/531-dhcp_opt_capwap.patch b/package/utils/busybox/patches/531-dhcp_opt_capwap.patch
new file mode 100644
index 0000000000..6c60159555
--- /dev/null
+++ b/package/utils/busybox/patches/531-dhcp_opt_capwap.patch
@@ -0,0 +1,18 @@
+--- a/networking/udhcp/common.c 2022-06-28 09:32:48.853072914 +0800
++++ b/networking/udhcp/common.c 2022-06-28 09:39:28.000000000 +0800
+@@ -54,6 +54,7 @@
+ { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
+ //TODO: not a string, but a set of LASCII strings:
+ // { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
++ { OPTION_IP | OPTION_LIST , 0x8A }, /* DHCP_CAPWAP */
+ { OPTION_STRING , 0x64 }, /* DHCP_PCODE */
+ { OPTION_STRING , 0x65 }, /* DHCP_TCODE */
+ #if ENABLE_FEATURE_UDHCP_RFC3397
+@@ -123,6 +124,7 @@
+ "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/
+ "bootfile" "\0" /* DHCP_BOOT_FILE */
+ // "userclass" "\0" /* DHCP_USER_CLASS */
++ "capwap" "\0" /* DHCP_CAPWAP */
+ "tzstr" "\0" /* DHCP_PCODE */
+ "tzdbstr" "\0" /* DHCP_TCODE */
+ #if ENABLE_FEATURE_UDHCP_RFC3397
--
2.34.1

View File

@@ -0,0 +1,43 @@
From 8e70ae7c71fb0a31b3b95f156b2d865ba8a07ae8 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 13 Jun 2025 12:06:48 +0200
Subject: [PATCH] fwtool: check for EST support if the cert was issued by insta
Signed-off-by: John Crispin <john@phrozen.org>
---
include/image-commands.mk | 3 ++-
package/base-files/files/lib/upgrade/fwtool.sh | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/image-commands.mk b/include/image-commands.mk
index d3c9cea293..b7a0d98d3d 100644
--- a/include/image-commands.mk
+++ b/include/image-commands.mk
@@ -85,7 +85,8 @@ metadata_json = \
"revision": "$(call json_quote,$(REVISION))", \
"target": "$(call json_quote,$(TARGETID))", \
"board": "$(call json_quote,$(if $(BOARD_NAME),$(BOARD_NAME),$(DEVICE_NAME)))" \
- } \
+ }, \
+ "est_supported": 1 \
}'
define Build/append-metadata
diff --git a/package/base-files/files/lib/upgrade/fwtool.sh b/package/base-files/files/lib/upgrade/fwtool.sh
index 8bd00a3332..a84eb96baf 100644
--- a/package/base-files/files/lib/upgrade/fwtool.sh
+++ b/package/base-files/files/lib/upgrade/fwtool.sh
@@ -51,6 +51,10 @@ fwtool_check_image() {
json_get_var compatmessage compat_message
[ -n "$imagecompat" ] || imagecompat="1.0"
+ if ! est_client fwtool; then
+ return 1
+ fi
+
# select correct supported list based on compat_version
# (using this ensures that compatibility check works for devices
# not knowing about compat-version)
--
2.34.1