From 0db44ca55bf7139228077c62871f416c68cc69f8 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 12 Jun 2025 11:14:13 +0200 Subject: [PATCH] cloud_discovery: add insta EST support Fixes: WIFI-14694 Signed-off-by: John Crispin --- .../certificates/files/etc/init.d/early_boot | 8 +- .../files/usr/bin/cloud_discovery | 109 +++++++++++++++++- .../tip-defaults/files/etc/ucentral/insta.pem | 6 + .../etc/ucentral/{cas.pem => openlan.pem} | 0 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 feeds/tip/tip-defaults/files/etc/ucentral/insta.pem rename feeds/tip/tip-defaults/files/etc/ucentral/{cas.pem => openlan.pem} (100%) diff --git a/feeds/tip/certificates/files/etc/init.d/early_boot b/feeds/tip/certificates/files/etc/init.d/early_boot index 2affba553..636fb5f40 100755 --- a/feeds/tip/certificates/files/etc/init.d/early_boot +++ b/feeds/tip/certificates/files/etc/init.d/early_boot @@ -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'` diff --git a/feeds/tip/cloud_discovery/files/usr/bin/cloud_discovery b/feeds/tip/cloud_discovery/files/usr/bin/cloud_discovery index e05c13ec2..43f849791 100755 --- a/feeds/tip/cloud_discovery/files/usr/bin/cloud_discovery +++ b/feeds/tip/cloud_discovery/files/usr/bin/cloud_discovery @@ -154,13 +154,107 @@ function discover_dhcp() { return !dhcp?.lease; } +function generate_csr() { + if (!fs.stat('/etc/ucentral/csr.nohdr.p10')) { + let pipe = fs.popen('openssl x509 -in /etc/ucentral/cert.pem -noout -subject'); + let subject = pipe.read("all"); + pipe.close(); + subject = replace(subject, 'subject=', '/'); + subject = replace(subject, ' = ', '='); + subject = replace(subject, ', ', '/'); + + let ret = system(`openssl req -subj "${subject}" -new -key /etc/ucentral/key.pem -out /etc/ucentral/csr.p10`); + if (ret) { + ulog(LOG_INFO, 'Failed to generate CSR\n'); + return 1; + } + + let input = fs.open('/etc/ucentral/csr.p10', 'r'); + let output = fs.open('/etc/ucentral/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) { + system('mount_certs'); + system(`cp ${path} /certificates/`); +} + +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; + } + return 0; +} + +function discover_operational_cert() { + if (fs.stat('/etc/ucentral/operational.pem')) { + ulog(LOG_INFO, 'Operational certificate is present\n'); + return 0; + } + + if (generate_csr()) + return 1; + + let ret = system('curl -X POST https://qaest.certificates.open-lan.org:8001/.well-known/est/simpleenroll -d @/etc/ucentral/csr.nohdr.p10 -H "Content-Type: application/pkcs10" --cert /etc/ucentral/cert.pem --key /etc/ucentral/key.pem --cacert /etc/ucentral/insta.pem -o /etc/ucentral/operational.nohdr.p7'); + if (ret) { + ulog(LOG_INFO, 'Failed to request operational certificate\n'); + return 1; + } + ulog(LOG_INFO, 'EST succeeded\n'); + + ret = p7_too_pem('/etc/ucentral/operational.nohdr.p7', '/etc/ucentral/operational.pem'); + if (ret) { + ulog(LOG_INFO, 'Failed to convert P7 to PEM\n'); + return 1; + } + ulog(LOG_INFO, 'Converted P7 to PEM\n'); + store_operational_cert('/etc/ucentral/operational.pem'); + return 0; +} + +function discover_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 /etc/ucentral/operational.ca.nohdr.p7'); + if (!ret) + ret = p7_too_pem('/etc/ucentral/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'); + return 0; +} + function redirector_lookup() { const path = '/tmp/ucentral.redirector'; ulog(LOG_INFO, 'Contact redirector service\n'); 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/cert.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); @@ -171,16 +265,19 @@ function redirector_lookup() { 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 +307,13 @@ function interval_handler() { if (discover_dhcp()) return; - if (discover_flash()) + if (discover_operational_cert()) + return; + + if (discover_operational_ca()) + return; + + if (!discover_flash()) return; redirector_lookup(); diff --git a/feeds/tip/tip-defaults/files/etc/ucentral/insta.pem b/feeds/tip/tip-defaults/files/etc/ucentral/insta.pem new file mode 100644 index 000000000..eeb4bd3a9 --- /dev/null +++ b/feeds/tip/tip-defaults/files/etc/ucentral/insta.pem @@ -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----- diff --git a/feeds/tip/tip-defaults/files/etc/ucentral/cas.pem b/feeds/tip/tip-defaults/files/etc/ucentral/openlan.pem similarity index 100% rename from feeds/tip/tip-defaults/files/etc/ucentral/cas.pem rename to feeds/tip/tip-defaults/files/etc/ucentral/openlan.pem