ci: cram: add support for lcm security test

Adding support for using CABundle/Certificates as defined by
TR181 for both remote registry and signature server.
Adding support for signature server authentication (username/password)
Adding support for setting custom User-Agent

References: PCF-2279, FEAT-300
Signed-off-by: Nabil BIZID <nabil.bizid@softathome.com>
This commit is contained in:
Nabil BIZID 2026-03-30 18:50:53 +02:00 committed by Hela Saadani
parent 2c14cd7d14
commit 9b943bbaab
21 changed files with 5473 additions and 5 deletions

View File

@ -0,0 +1,226 @@
## Setup test configuration
Setup the test configuration:
$ alias R="${CRAM_REMOTE_COMMAND:-}"
$ alias C="${CRAM_REMOTE_COPY:-}"
$ S=". /tmp/script_functions.sh && . /tmp/security_functions.sh"
$ R logger -t cram "Starting LCM security test"
$ TEST_RESOURCES="${TESTDIR}/security_resources"
$ python3 -u ${TEST_RESOURCES}/https_signature_server.py > signature-server-$LABGRID_TARGET.log 2>&1 &
$ SIGNATURE_SERVER_PID=$!
$ sleep 5
$ C ${TESTDIR}/script_functions.sh root@${TARGET_LAN_IP}:/tmp/script_functions.sh 2>/dev/null
$ C ${TEST_RESOURCES}/security_functions.sh root@${TARGET_LAN_IP}:/tmp/security_functions.sh 2>/dev/null
$ R "mkdir -p /tmp/lcm_root_ca /etc/amx/tr181-security/extensions" > /dev/null
$ C ${TEST_RESOURCES}/01_security_cram_lcm.odl root@${TARGET_LAN_IP}:/etc/amx/tr181-security/extensions/01_cram_lcm.odl 2>/dev/null
$ C ${TEST_RESOURCES}/timingila.odl root@${TARGET_LAN_IP}:/tmp/softwaremodules_default.odl 2>/dev/null
$ C ${TEST_RESOURCES}/sign_test_pub.asc root@${TARGET_LAN_IP}:/tmp/sign_test_pub.asc 2>/dev/null
$ C ${TEST_RESOURCES}/lcm_servers_root_ca1.crt root@${TARGET_LAN_IP}:/usr/share/ca-certificates/lcm_servers_root_ca1.crt 2>/dev/null
$ C ${TEST_RESOURCES}/ca_bundle.crt root@${TARGET_LAN_IP}:/usr/share/ca-certificates/ca_bundle.crt 2>/dev/null
$ CSR_NAME="lcm_cert_client.csr"
$ CA_ROOT_NAME="${TEST_RESOURCES}/lcm_test_root_ca_client"
$ C ${TESTDIR}/event.lua root@${TARGET_LAN_IP}:/tmp/event.lua 2>/dev/null
$ C ${TESTDIR}/usp-cli/usp-cli.conf root@${TARGET_LAN_IP}:/etc/amx/cli/usp-test-cli.conf 2>/dev/null
$ C ${TESTDIR}/usp-cli/usp-cli.init root@${TARGET_LAN_IP}:/etc/amx/cli/usp-test-cli.init 2>/dev/null
$ R "if [ ! -f /usr/bin/usp-test-cli ] ; then ln -s amx-cli /usr/bin/usp-test-cli; fi"
##### GENERAL SECURITY SETUP SECTION
Configure HSM with necessary slots, keys and generate a CSR:
$ R "${S} && configure_hsm"
Token created
Private key created
CSR generated
Copy the CSR from the device, sign it with the local CA to produce a client certificate, then provision the certificate back to the device:
$ C root@${TARGET_LAN_IP}:/tmp/${CSR_NAME} /tmp/${CSR_NAME} 2>/dev/null
$ openssl x509 -req -in "/tmp/${CSR_NAME}" -CA "${CA_ROOT_NAME}.crt" -CAkey "${CA_ROOT_NAME}.key" -set_serial 0x123456789 -CAcreateserial -out /tmp/lcm_cert_client.crt -days 365 -sha256 >/dev/null 2>&1 && echo "Certificate signed successfully"
Certificate signed successfully
$ C /tmp/lcm_cert_client.crt root@${TARGET_LAN_IP}:/etc/config/autocert/ 2>/dev/null
$ R "${S} && configure_security ${TARGET_LAN_TEST_HOST}" > /dev/null
###### TEST SECTION
Subscribe to the DUStateChange event to capture installation results:
$ R "${S} && configure_datamodel set_subscription" > /dev/null
Test container installation using HTTP for the image signature server:
$ R "${S} && configure_datamodel set_http"
[{"Device.SoftwareModules.Config.":{"DUSignatureProtocols":"HTTP"}}]
$ R "${S} && install_basic_container --signature http://signature.server1.local.com:8888/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation using HTTPS for the image signature server:
$ R "${S} && configure_datamodel set_https"
[{"Device.SoftwareModules.Config.":{"DUSignatureProtocols":"HTTPS"}}]
$ R "${S} && install_basic_container --signature https://signature.server1.local.com:5443/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test that a custom User-Agent header value is sent in HTTP requests to the signature server:
$ R "${S} && configure_datamodel set_useragent"
[{"Rlyeh.":{"UserAgent":"my custom User-Agent value"}}]
$ R "${S} && install_basic_container --signature https://signature.server1.local.com:5443/signature" > /dev/null
$ cat /tmp/lcm_http_useragent.txt
my custom User-Agent value
$ rm -f /tmp/lcm_http_useragent.txt
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation with Basic authentication on the signature server:
$ R "${S} && install_basic_container --signature_user --signature_pwd --signature https://signature.server1.local.com:6443/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation with Token/Bearer authentication using a wrong password - expect authentication failure:
$ R "${S} && listen_dustatechange"
$ R "${S} && install_basic_container_no_wait --signature_user --signature_pwd wrongpass --signature https://signature.server1.local.com:7443/signature" > /dev/null
$ R "${S} && filtered_event"
FaultCode = 7036
FaultString = "Signature check for [*] failed [Authentication failed: * URL [*]]" (glob)
CurrentState = "Failed"
OperationPerformed = "Install"
Test container installation with Token/Bearer authentication using a correct password - expect success:
$ R "${S} && install_basic_container --signature_user --signature_pwd --signature https://signature.server1.local.com:7443/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation fails when the registry is configured with a wrong CA bundle:
$ R "${S} && configure_datamodel docker_repo_root_ca1"
[{"Device.SoftwareModules.Config.Repository.*.":{"CABundle":"Device.Security.CABundle.*"}}] (glob)
$ R "${S} && listen_dustatechange"
$ R "${S} && install_basic_container_no_wait" > /dev/null
$ R "${S} && filtered_event"
FaultCode = 7002
FaultString = "Pull image [*] failed [*]" (glob)
CurrentState = "Failed"
OperationPerformed = "Install"
Test container installation succeeds when the registry is configured with the correct CA bundle:
$ R "${S} && configure_datamodel docker_repo_ca_bundle"
[{"Device.SoftwareModules.Config.Repository.*.":{"CABundle":"Device.Security.CABundle.*"}}] (glob)
$ R "${S} && install_basic_container" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation fails when the signature server is configured with a wrong CA bundle:
$ R "${S} && listen_dustatechange"
$ R "${S} && install_basic_container_no_wait --signature https://signature.server2.local.com:9443/signature" > /dev/null
$ R "${S} && filtered_event"
FaultCode = 7036
FaultString = "Signature check for [*] failed [Authentication failed: * URL [https://signature.server2.local.com:*/signature*]]" (glob)
CurrentState = "Failed"
OperationPerformed = "Install"
Test container installation succeeds when the signature server is configured with the correct CA bundle:
$ R "${S} && install_basic_container --signature https://signature.server1.local.com:5443/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation fails when connecting to an mTLS signature server without providing a client certificate:
$ R "${S} && configure_datamodel no_client_cert"
[{"Device.SoftwareModules.Config.Repository.*.":{"Certificate":""}}] (glob)
$ R "${S} && listen_dustatechange"
$ R "${S} && install_basic_container_no_wait --signature https://signature.server1.local.com:8443/signature" > /dev/null
$ R "${S} && filtered_event"
FaultCode = 7036
FaultString = "Signature check for [*] failed [Authentication failed: * URL [https://signature.server1.local.com:*/signature*]]" (glob)
CurrentState = "Failed"
OperationPerformed = "Install"
Test container installation succeeds when connecting to an mTLS signature server with a valid client certificate:
$ R "${S} && configure_datamodel set_client_cert"
[{"Device.SoftwareModules.Config.Repository.*.":{"Certificate":"Device.Security.Certificate.*"}}] (glob)
$ R "${S} && install_basic_container --signature_user --signature_pwd --signature https://signature.server1.local.com:8443/signature" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation suceeds when using valid default CA bundle configuration:
$ R "${S} && configure_datamodel disable_docker_repo"
[{"Device.SoftwareModules.Config.Repository.*.":{"Enable":false}}] (glob)
$ R "${S} && install_basic_container" > /dev/null
$ R "${S} && get_container_info --uuid"
Active
prplos-v1
prpl-foundation/prplos/prplos/prplos/lcm-test-* (glob)
$ R "${S} && uninstall_ctr_and_check --uuid --retaindata false"
[1]
Test container installation fails when using wrong default CA bundle configuration:
$ R "${S} && configure_datamodel set_default_ca_wrong"
[{"Device.SoftwareModules.Config.":{"CABundle":"Device.Security.CABundle.*"}}] (glob)
$ R "${S} && listen_dustatechange"
$ R "${S} && install_basic_container_no_wait" > /dev/null
$ R "${S} && filtered_event"
FaultCode = 7002
FaultString = "Pull image [*] failed [*]" (glob)
CurrentState = "Failed"
OperationPerformed = "Install"
##### GENERAL CLEANUP SECTION
Clear all configuration and environment:
$ R "${S} && cleanup_security"
$ kill $SIGNATURE_SERVER_PID 2>/dev/null || true
$ R logger -t cram "LCM security test finished"

View File

@ -17,6 +17,8 @@ DEFAULT_USERNAME=""
DEFAULT_PASSWORD=""
DEFAULT_RETAINDATA="false"
DEFAULT_ENVVAR='[{Key="ENVVAR_KEY1", Value="ENVVAR_VALUE1"}, {Key="ENVVAR_KEY2", Value="ENVVAR_VALUE2"}]'
DEFAULT_SIGNATURE_PASSWORD="secret"
DEFAULT_SIGNATURE_USERNAME="admin"
CLI_JSON="ba-cli -l -j"
CLI="ba-cli"
@ -259,11 +261,13 @@ value_or_default() {
install_update_ctr_with_params() {
params=$@
operation=$1
no_wait=$2
if [ "${operation}" != "install" ] && [ "${operation}" != "update" ]; then
echo "Unknown operation: $operation"
return
fi
shift
shift
str_params=""
uuid=""
@ -289,14 +293,15 @@ install_update_ctr_with_params() {
str_params=$(concat_comma_string "${str_params}" "URL = \"${value}\"")
elif [ "${key}" = "name" ]; then
ctr_name=$(get_container_by_name ${value})
ctr_version=$(get_container_version_by_name ${value})
ctr_version=$(get_container_version_by_name ${value})
str_params=$(concat_comma_string "${str_params}" "URL = \"${DEFAULT_URL}/${ctr_name}:${ctr_version}\"")
elif [ "${key}" = "url_arch" ]; then
ctr_arch=$(get_arch_name)
str_params=$(concat_comma_string "${str_params}" "URL = \"${DEFAULT_URL}/lcm_tests/${ctr_arch}_${value}\"")
elif [ "${key}" = "version" ]; then
ctr_name=$(get_container_name)
str_params=$(concat_comma_string "${str_params}" "URL = \"${DEFAULT_URL}/prplos/${ctr_name}:${value}\"")
ctr_version="${value}"
str_params=$(concat_comma_string "${str_params}" "URL = \"${DEFAULT_URL}/prplos/${ctr_name}:${ctr_version}\"")
elif [ "${key}" = "uuid" ]; then
value=$(value_or_default "${value_missing}" "${DEFAULT_UUID}" "${value}")
str_params=$(concat_comma_string "${str_params}" "UUID = ${value}")
@ -348,6 +353,14 @@ install_update_ctr_with_params() {
str_params=$(concat_comma_string "${str_params}" "RequiredUserRoles = \"${value}\"")
elif [ "${key}" = "moduleversion" ]; then
str_params=$(concat_comma_string "${str_params}" "ModuleVersion = \"${value}\"")
elif [ "${key}" = "signature" ]; then
str_params=$(concat_comma_string "${str_params}" "Signature = \"${value}_${ctr_name}_${ctr_version}\"")
elif [ "${key}" = "signature_pwd" ]; then
value=$(value_or_default "${value_missing}" "${DEFAULT_SIGNATURE_PASSWORD}" "${value}")
str_params=$(concat_comma_string "${str_params}" "SignaturePassword = \"${value}\"")
elif [ "${key}" = "signature_user" ]; then
value=$(value_or_default "${value_missing}" "${DEFAULT_SIGNATURE_USERNAME}" "${value}")
str_params=$(concat_comma_string "${str_params}" "SignatureUsername = \"${value}\"")
elif [ "${key}" = "debugargs" ]; then
debugargs=$(value_or_default "${value_missing}" "1" "${value}")
else
@ -372,7 +385,9 @@ install_update_ctr_with_params() {
wait_ctr_down
fi
wait_ctr_up $params
if [ "$no_wait" == "false" ]; then
wait_ctr_up $params
fi
}
uninstall_ctr() {
@ -902,12 +917,16 @@ get_ctr_type() {
}
install_ctr_no_wait() {
install_update_ctr_with_params install true "$@"
}
install_ctr() {
install_update_ctr_with_params install "$@"
install_update_ctr_with_params install false "$@"
}
update_ctr() {
install_update_ctr_with_params update "$@"
install_update_ctr_with_params update false "$@"
}
## Create the host object resources used for the default HostObject config
@ -1188,3 +1207,48 @@ cleanup_appdata() {
}
##
## install_basic_container() - Install a container with default parameters and wait for it to become active.
##
## Fixed defaults applied by this function:
## --version prplos-v1 : Container image version to install.
## --ee : Execution environment (defaults to DEFAULT_EE = "generic" if not overridden).
## --uuid : Deployment unit UUID (defaults to DEFAULT_UUID if not overridden).
## --privileged true : Container is started in privileged mode.
##
## Parameters:
## "$@" : Optional extra arguments forwarded verbatim to install_ctr.
## Any supported install_ctr argument (--url, --network, --hostobject,
## --appdata, --envvar, --retaindata, --usprequired, etc.) can be supplied
## here to override the defaults above.
##
## Example:
## install_basic_container
## install_basic_container --envvar --network '{ShareParentNetwork = "true"}'
##
install_basic_container() {
install_ctr --version prplos-v1 --ee --uuid --privileged true "$@" > /dev/null
}
##
## install_basic_container_no_wait() - Install a container with default parameters without waiting for it to become active.
##
## Fixed defaults applied by this function:
## --version prplos-v1 : Container image version to install.
## --ee : Execution environment (defaults to DEFAULT_EE = "generic" if not overridden).
## --uuid : Deployment unit UUID (defaults to DEFAULT_UUID if not overridden).
## --privileged true : Container is started in privileged mode.
##
## Parameters:
## "$@" : Optional extra arguments forwarded verbatim to install_ctr_no_wait.
## Any supported install_ctr argument (--url, --network, --hostobject,
## --appdata, --envvar, --retaindata, --usprequired, etc.) can be supplied
## here to override the defaults above.
##
## Example:
## install_basic_container_no_wait
## install_basic_container_no_wait --envvar
##
install_basic_container_no_wait() {
install_ctr_no_wait --version prplos-v1 --ee --uuid --privileged true "$@"
}

View File

@ -0,0 +1,12 @@
%populate{
object 'Security.CABundle' {
instance add(0, 'ca_bundle', Name = "ca_bundle", Enable=1) {
parameter CAFileURI = "file:///usr/share/ca-certificates/ca_bundle.crt";
parameter CACertificates = "Security.Certificate.[SerialNumber==\"5EC3B7A6437FA4E0\"].";
}
instance add(0, 'root_ca1', Name = "root_ca1", Enable=1) {
parameter CAFileURI = "file:///usr/share/ca-certificates/lcm_servers_root_ca1.crt";
parameter CACertificates = "Security.Certificate.[SerialNumber==\"5C467BFB94E62AC5A899BBFFC605E0938F262832\"].";
}
}
}

View File

@ -0,0 +1,229 @@
# LCM Security Test Resources
This directory contains resources required for the LCM security test (`040-lcm-security.t`). The test validates secure container deployment using various authentication methods, certificate validation, and image signature verification. The resources are organized into device configuration files and signature server simulation tools.
## Table of Contents
- [Device Configuration Files](#device-configuration-files)
- [File Descriptions](#file-descriptions)
- [Certificate Authority (CA) Files](#certificate-authority-ca-files)
- [ca_bundle.crt](#ca_bundlecrt)
- [Image Signature Files](#image-signature-files)
- [Configuration Files](#configuration-files)
- [Signature Server Simulation Tool](#signature-server-simulation-tool)
- [https_signature_server.py](#https_signature_serverpy)
- [Certificate Authority (CA)](#certificate-authority-ca-1)
- [Server Certificates](#server-certificates)
## Device Configuration Files
Files required for setting up security infrastructure on the device:
| File | Type | Purpose |
|------|------|---------|
| `lcm_test_root_ca_client.crt` | CA Certificate | Root CA for signing client certificates |
| `lcm_test_root_ca_client.key` | CA Private Key | Private key for client certificate CA |
| `ca_bundle.crt` | CA Bundle | Common trusted CAs for signature/registry validation |
| `sign_test_pub.asc` | GPG Public Key | Public key for verifying container image signatures |
| `signature_lcm-test-x86-64_prplos-v1` | Image Signature | GPG signature for x86-64 container images |
| `signature_lcm-test-ipq807x-generic_prplos-v1` | Image Signature | GPG signature for ipq807x container images |
### File Descriptions
#### Certificate Authority (CA) Files
##### `lcm_test_root_ca_client.crt` / `lcm_test_root_ca_client.key`
- **Role**: Root CA for signing client certificates
- **Usage**: Used to sign the client certificate CSR generated on the device
- **Test Context**: The test generates a CSR on the device via SoftHSM, copies it to the host, signs it with this CA, and provisions the signed certificate back to the device for mTLS authentication
- **Example generation**:
```bash
openssl genrsa -out lcm_test_root_ca_client.key 3072
openssl req -new -x509 -days 3650 -key lcm_test_root_ca_client.key \
-out lcm_test_root_ca_client.crt \
-subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=Test/CN=LCM Test Root CA Client"
```
#### `ca_bundle.crt`
- **Role**: CA bundle containing the most common trusted CAs
- **Usage**: Referenced in the device datamodel as `Device.Security.CABundle.[Name == "ca_bundle"]`
- **Test Context**: Used for successful signature verification when the correct CA bundle is configured
- **ODL Config**: Configured in `01_security_cram_lcm.odl` with certificate reference `Security.Certificate.[SerialNumber=="5EC3B7A6437FA4E0"]`
##### Generating CA Bundle
The `ca_bundle.crt` is typically a concatenation of multiple trusted CA certificates:
```bash
# Download common CA certificates or concatenate your own
cat /etc/ssl/certs/ca-certificates.crt > ca_bundle.crt
# Or create a custom bundle
cat lcm_servers_root_ca1.crt >> ca_bundle.crt
cat other_trusted_ca.crt >> ca_bundle.crt
```
#### Image Signature Files
##### `sign_test_pub.asc`
- **Role**: GPG public key for verifying container image signatures
- **Key Details**: "Test signing key <lcm_test_signing@softathome.com>"
- **Usage**: Installed to `/usr/share/rlyeh/keys/` on the device
- **Test Context**: Rlyeh uses this public key to verify signatures downloaded from the signature server
- **Format**: ASCII-armored PGP public key block
- **Example generation**:
```bash
# Generate GPG key pair
gpg --quick-generate-key --pinentry-mode=loopback --passphrase "" "LCM signing key <lcm_test_signing@softathome.com>" rsa2048 sign never
# Export public key
gpg --armor --export lcm_test_signing@softathome.com > sign_test_pub.asc
```
##### Image Signature Files (by Architecture)
**Files**: `signature_lcm-test-x86-64_prplos-v1` and `signature_lcm-test-ipq807x-generic_prplos-v1`
- **Role**: GPG-signed signature files for `lcm-test-x86-64` and `lcm-test-ipq807x-generic` container images (both version `prplos-v1`)
- **Usage**: Served by the signature server and verified against the container image manifest
- **Format**: JSON signature created by skopeo standalone-sign
- **Example Generation**:
```bash
# Download the container image using skopeo
DOCKER_URL="docker://registry.gitlab.com/prpl-foundation/prplos/prplos/prplos/lcm-test-x86-64:prplos-v1"
IMAGE_NAME="lcm-test-x86-64"
IMAGE_VERSION="prplos-v1"
DEST_DIR="/tmp/${IMAGE_NAME}_${IMAGE_VERSION}"
FINGERPRINT=$(gpg --with-colons --fingerprint lcm_test_signing@softathome.com | awk -F: '/^fpr:/ {print $10; exit}')
mkdir -p ${DEST_DIR}
skopeo copy ${DOCKER_URL} dir:${DEST_DIR}
# Sign the manifest using skopeo (requires GPG key already generated)
NO_PROTO=$(echo "$DOCKER_URL" | sed 's/^docker:\/\///')
skopeo standalone-sign ${DEST_DIR}/manifest.json ${NO_PROTO} \
${FINGERPRINT} --output signature_lcm-test-x86-64_prplos-v1
```
##### Verify Signature (for testing)
```bash
# Verify a signature using skopeo
skopeo standalone-verify ${DEST_DIR}/manifest.json \
${NO_PROTO} ${FINGERPRINT} --output signature_lcm-test-x86-64_prplos-v1
```
#### Configuration Files
##### `01_security_cram_lcm.odl`
- **Role**: ODL configuration for TR-181 security datamodel extensions
- **Usage**: Copied to `/etc/amx/tr181-security/extensions/01_cram_lcm.odl` on the device
- **Content**: Defines two CA bundle instances:
- `ca_bundle`: Points to `/usr/share/ca-certificates/ca_bundle.crt`
- `root_ca1`: Points to `/usr/share/ca-certificates/lcm_servers_root_ca1.crt`
- **Test Context**: Populates the `Device.Security.CABundle` datamodel with CA certificates that can be referenced by repository configurations
##### `timingila.odl`
- **Role**: Software modules configuration for the Timingila service
- **Usage**: Copied to `/etc/config/softwaremodules/odl/timingila.odl` on the device
- **Test Context**: Configures default software module configuration for the test
## Signature Server Simulation Tool
Files used by `https_signature_server.py` to simulate signature servers:
| File | Type | Purpose |
|------|------|---------|
| `lcm_servers_root_ca1.crt` | CA Certificate | Root CA for signature.server1.local.com |
| `lcm_servers_root_ca1.key` | CA Private Key | Private key for server1 CA |
| `lcm_servers_root_ca2.crt` | CA Certificate | Root CA for signature.server2.local.com (wrong CA testing) |
| `lcm_servers_root_ca2.key` | CA Private Key | Private key for server2 CA |
| `server_1.crt` | Server Certificate | TLS certificate for signature.server1.local.com |
| `server_1.key` | Server Private Key | Private key for server1 TLS |
| `server_2.crt` | Server Certificate | TLS certificate for signature.server2.local.com |
| `server_2.key` | Server Private Key | Private key for server2 TLS |
#### `https_signature_server.py`
- **Role**: Python-based HTTP/HTTPS simulation server for serving container image signatures
- **Features**:
- Multiple authentication methods: Basic, Bearer/Token, none
- TLS/SSL support with configurable certificates
- mTLS (mutual TLS) support for client certificate validation
- User-Agent header capture for testing
- **Server Configurations**:
| Port | Protocol | Authentication | Server | Notes |
|------|----------|----------------|--------|-------|
| 5443 | HTTPS | No authen | signature.server1.local.com | |
| 6443 | HTTPS | Basic | signature.server1.local.com | |
| 7443 | HTTPS | Bearer | signature.server1.local.com | |
| 8443 | HTTPS | mTLS + Bearer | signature.server1.local.com | Requires client cert |
| 8888 | HTTP | Bearer | signature.server1.local.com | Non-encrypted |
| 9443 | HTTPS | Bearer | signature.server2.local.com | Wrong CA test |
- **Usage**: Started before running the security test to serve signature files
- **Authentication Credentials**: Username/password: `admin:secret`
- **Test Context**: Simulates a production signature server with various security configurations serving files prefixed with `signature`
- **Note**: Test domains (signature.server1.local.com and signature.server2.local.com) are fake domains and must be resolved on client device (via `/etc/hosts`) to the IP address of the host where the script is run.
- **Example command**:
```bash
# Start the signature server (runs all configured ports)
python3 https_signature_server.py
```
#### Certificate Authority (CA)
##### `lcm_servers_root_ca1.crt` / `lcm_servers_root_ca1.key`
- **Role**: Root CA for signing server certificates (signature.server1.local.com)
- **Usage**: Referenced in the device datamodel as `Device.Security.CABundle.[Name == "root_ca1"]`
- **Test Context**: Used to validate HTTPS connections to signature.server1.local.com
- **ODL Config**: Configured in `01_security_cram_lcm.odl` with serial number `5C467BFB94E62AC5A899BBFFC605E0938F262832`
- **Example generation**:
```bash
openssl genrsa -out lcm_servers_root_ca1.key 3072
openssl req -new -x509 -days 3650 -key lcm_servers_root_ca1.key \
-out lcm_servers_root_ca1.crt \
-subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=Test/CN=LCM Servers Root CA 1"
```
##### `lcm_servers_root_ca2.crt` / `lcm_servers_root_ca2.key`
- **Role**: Root CA for signing server certificates (signature.server2.local.com)
- **Usage**: Used for negative testing - validates that using the wrong CA bundle causes signature verification to fail
- **Test Context**: Server2 uses a different CA to test CA bundle validation failures
- **Example generation**:
```bash
openssl genrsa -out lcm_servers_root_ca2.key 3072
openssl req -new -x509 -days 3650 -key lcm_servers_root_ca2.key \
-out lcm_servers_root_ca2.crt \
-subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=Test/CN=LCM Servers Root CA 2"
```
#### Server Certificates
##### `server_1.crt` / `server_1.key`
- **Role**: TLS certificate and private key for `signature.server1.local.com`
- **Usage**: Used by the HTTPS signature server running on multiple ports (5443, 6443, 7443, 8443, 9443)
- **Example generation**:
```bash
openssl genrsa -out server_1.key 2048
openssl req -new -key server_1.key -out server_1.csr \
-subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=Test/CN=signature.server1.local.com"
openssl x509 -req -in server_1.csr \
-CA lcm_servers_root_ca1.crt -CAkey lcm_servers_root_ca1.key \
-CAcreateserial -out server_1.crt -days 36500 -sha256
```
##### `server_2.crt` / `server_2.key`
- **Role**: TLS certificate and private key for `signature.server2.local.com`
- **Usage**: Used for negative CA bundle testing
- **Example generation**:
```bash
openssl genrsa -out server_2.key 2048
openssl req -new -key server_2.key -out server_2.csr \
-subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=Test/CN=signature.server2.local.com"
openssl x509 -req -in server_2.csr \
-CA lcm_servers_root_ca2.crt -CAkey lcm_servers_root_ca2.key \
-CAcreateserial -out server_2.crt -days 36500 -sha256
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,400 @@
#!/bin/python3
"""
HTTP/HTTPS signature server simulator for LCM security testing.
Serves container image signature files with multiple authentication methods (Basic, Bearer, mTLS)
and SSL/TLS configurations across different ports. Used to test signature verification workflows
in the LCM security test suite.
"""
from http.server import BaseHTTPRequestHandler, HTTPServer
import base64
import os
from urllib.parse import urlparse
import ssl
import threading
import time
# Get the directory where this script is located
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
config1 = {
"enable_basic": False,
"enable_bearer": True,
# Basic auth
"basic_realm": "Secure File Server",
"username": "admin",
"password": "secret",
# Bearer auth
"bearer_service": "example-file-server",
"bearer_scope": "files:read",
"bearer_token": '{"token":"mysecrettoken","expires_in":300}',
"bearer_token_expected": "mysecrettoken",
"signature_dir": SCRIPT_DIR
}
config2 = {
"enable_basic": False,
"enable_bearer": True,
# Basic auth
"basic_realm": "Secure File Server",
"username": "admin",
"password": "secret",
# Bearer auth
"bearer_service": "example-file-server",
"bearer_scope": "files:read",
"bearer_token": '{"token":"mysecrettoken","expires_in":300}',
"bearer_token_expected": "mysecrettoken",
"signature_dir": SCRIPT_DIR
}
config3 = {
"enable_basic": False,
"enable_bearer": True,
# Basic auth
"basic_realm": "Secure File Server",
"username": "admin",
"password": "secret",
# Bearer auth
"bearer_service": "example-file-server",
"bearer_scope": "files:read",
"bearer_token": '{"token":"mysecrettoken","expires_in":300}',
"bearer_token_expected": "mysecrettoken",
"signature_dir": SCRIPT_DIR
}
config4 = {
"enable_basic": True,
"enable_bearer": False,
# Basic auth
"basic_realm": "Secure File Server",
"username": "admin",
"password": "secret",
"signature_dir": SCRIPT_DIR
}
config5 = {
"enable_basic": False,
"enable_bearer": False,
"signature_dir": SCRIPT_DIR
}
class AuthHandler(BaseHTTPRequestHandler):
def unauthorized(self):
self.send_response(401)
if self.CONFIG["enable_basic"]:
self.send_header(
"WWW-Authenticate",
f'Basic realm="{self.CONFIG["basic_realm"]}"'
)
if self.CONFIG["enable_bearer"]:
self.send_header(
"WWW-Authenticate",
'Bearer '
f'realm="{self.CONFIG["bearer_realm"]}", '
f'service="{self.CONFIG["bearer_service"]}", '
f'scope="{self.CONFIG["bearer_scope"]}"'
)
self.end_headers()
def check_basic(self, encoded):
try:
decoded = base64.b64decode(encoded).decode()
username, password = decoded.split(":", 1)
except Exception:
return False
return (
username == self.CONFIG["username"]
and password == self.CONFIG["password"]
)
def check_bearer(self, token):
return token == self.CONFIG["bearer_token_expected"]
def authenticate(self):
# If no authentication is enabled, allow access
if not self.CONFIG["enable_basic"] and not self.CONFIG["enable_bearer"]:
return True
auth_header = self.headers.get("Authorization")
if not auth_header:
return False
try:
scheme, value = auth_header.split(" ", 1)
except ValueError:
return False
if scheme == "Basic" and self.CONFIG["enable_basic"]:
return self.check_basic(value)
if scheme == "Bearer" and self.CONFIG["enable_bearer"]:
return self.check_bearer(value)
return False
def serve_token(self):
auth_header = self.headers.get("Authorization")
if not auth_header:
self.send_response(401)
self.send_header("WWW-Authenticate", 'Basic realm="Token"')
self.end_headers()
return
try:
scheme, encoded = auth_header.split(" ", 1)
if scheme != "Basic":
raise ValueError()
decoded = base64.b64decode(encoded).decode()
username, password = decoded.split(":", 1)
except Exception:
self.send_response(400)
self.end_headers()
return
# validate user
if (
username != self.CONFIG.get("username")
or password != self.CONFIG.get("password")
):
self.send_response(403)
self.end_headers()
return
token = self.CONFIG["bearer_token"].encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(token)))
self.end_headers()
if self.command != "HEAD":
self.wfile.write(token)
def serve_signature(self, name):
base_dir = self.CONFIG["signature_dir"] # change from single file → directory
# Build full path
path = os.path.join(base_dir, name)
if not os.path.exists(path):
self.send_response(404)
self.end_headers()
return
size = os.path.getsize(path)
self.send_response(200)
self.send_header("Content-Type", "application/octet-stream")
self.send_header("Content-Length", str(size))
self.end_headers()
if self.command != "HEAD":
with open(path, "rb") as f:
self.wfile.write(f.read())
def do_HEAD(self):
useragent = self.headers.get("User-agent")
if useragent:
print(f"Request received from: {useragent}")
with open('/tmp/lcm_http_useragent.txt', 'w') as file:
# Write a string into the file
file.write(f"{useragent}\n")
parsed = urlparse(self.path)
if parsed.path == "/token":
self.serve_token()
return
if parsed.path.startswith("/signature"):
if not self.authenticate():
self.unauthorized()
return
name = parsed.path
if name.startswith("/"):
name = name[1:]
self.serve_signature(name)
return
# Unknown path - return 404
self.send_response(404)
self.end_headers()
def do_GET(self):
useragent = self.headers.get("User-agent")
if useragent:
print(f"Request received from {useragent}")
parsed = urlparse(self.path)
if parsed.path == "/token":
self.serve_token()
return
if parsed.path.startswith("/signature"):
if not self.authenticate():
self.unauthorized()
return
name = parsed.path
if name.startswith("/"):
name = name[1:]
self.serve_signature(name)
return
# Unknown path - return 404
self.send_response(404)
self.end_headers()
def make_handler(config):
class AuthHandlerWithConfig(AuthHandler):
CONFIG = config # attach config to the class
return AuthHandlerWithConfig
def get_common_name(certificate):
cert = ssl._ssl._test_decode_cert(certificate)
subject = cert.get("subject", [])
cn = None
for item in subject:
for key, value in item:
if key == "commonName":
cn = value
return cn
def run_server(port, certfile, keyfile, config, clientCA=None):
handler_class = make_handler(config)
server = HTTPServer(("0.0.0.0", port), handler_class)
if certfile != None:
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
if clientCA:
# Trust the CA that issued client certificates
context.load_verify_locations(cafile=clientCA)
# Require client certificate (mTLS)
context.verify_mode = ssl.CERT_REQUIRED
else:
# Explicitly disable client cert requirement (good practice)
context.verify_mode = ssl.CERT_NONE
server.socket = context.wrap_socket(server.socket, server_side=True)
mode = "mTLS MANDATORY" if clientCA else "No mTLS"
used_cert= f"cert is {certfile}"
cn = get_common_name(certfile)
config["bearer_realm"] = f"https://{cn}:{port}/token"
auth_mode = "No authentication"
if config["enable_basic"]:
auth_mode = "Basic authentication"
if config["enable_bearer"]:
auth_mode = "Token/Bearer authentication"
if certfile == None:
print(f"HTTP server running on http://0.0.0.0:{port} ({auth_mode})")
else:
print(f"HTTPS server running on https://{cn}:{port} ({used_cert}, {mode} with {auth_mode})")
server.serve_forever()
def main():
"""Start all HTTPS servers with different configurations."""
print("Starting HTTPS signature servers...")
# No auth server on port 5443
threading.Thread(
target=run_server,
args=(5443, os.path.join(SCRIPT_DIR, "server_1.crt"), os.path.join(SCRIPT_DIR, "server_1.key"), config5),
daemon=True
).start()
time.sleep(0.2)
# Basic auth server on port 6443
threading.Thread(
target=run_server,
args=(6443, os.path.join(SCRIPT_DIR, "server_1.crt"), os.path.join(SCRIPT_DIR, "server_1.key"), config4),
daemon=True
).start()
time.sleep(0.2)
# Bearer/Token auth server on port 7443
threading.Thread(
target=run_server,
args=(7443, os.path.join(SCRIPT_DIR, "server_1.crt"), os.path.join(SCRIPT_DIR, "server_1.key"), config3),
daemon=True
).start()
time.sleep(0.2)
# mTLS with bearer auth server on port 8443
threading.Thread(
target=run_server,
args=(8443, os.path.join(SCRIPT_DIR, "server_1.crt"), os.path.join(SCRIPT_DIR, "server_1.key"), config1, os.path.join(SCRIPT_DIR, "lcm_test_root_ca_client.crt")),
daemon=True
).start()
time.sleep(0.2)
# Different CA server on port 9443
threading.Thread(
target=run_server,
args=(9443, os.path.join(SCRIPT_DIR, "server_2.crt"), os.path.join(SCRIPT_DIR, "server_2.key"), config2),
daemon=True
).start()
time.sleep(0.2)
# HTTP server on port 8888 with no auth
threading.Thread(
target=run_server,
args=(8888, None, None, config5),
daemon=True
).start()
time.sleep(0.2)
print("All servers started. Press Ctrl+C to stop.")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nShutting down servers...")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF0zCCA7ugAwIBAgIUXEZ7+5TmKsWombv/xgXgk48mKDIwDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCQkUxETAPBgNVBAgMCFdpamdtYWFsMREwDwYDVQQHDAhX
aWpnbWFhbDETMBEGA1UECgwKU29mdEF0SG9tZTELMAkGA1UECwwCSVQxITAfBgNV
BAMMGExDTV9URVNUX1JPT1RfQ0FfU0VSVkVSMTAgFw0yNjAzMjkyMDI2MDFaGA8y
MTI2MDMwNTIwMjYwMVoweDELMAkGA1UEBhMCQkUxETAPBgNVBAgMCFdpamdtYWFs
MREwDwYDVQQHDAhXaWpnbWFhbDETMBEGA1UECgwKU29mdEF0SG9tZTELMAkGA1UE
CwwCSVQxITAfBgNVBAMMGExDTV9URVNUX1JPT1RfQ0FfU0VSVkVSMTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMN37WEs619Up785nwSUjG5+aqnsNQd0
9Nwg4b3S0ZPq3NPJFZyehsjyDT51EWaja8nxa/6HJkHTKZdFTgy02WzYEoEW9toN
PMyORXZwuc0jNoW52AgS2YMxtSkQM8WsfjGhROLMcKyf+sdUR92ImiPnQbDfZCbU
SF8Z+qKVuoIF9gqE3+gR/CAcBXOicUPE5dUEuQmi0T8eLnjCRNsBZ5rIBgK9bCP9
L10h7J5wu929zD7hguKeb8zShGZO3Qmf3jPJC5+mWLzaFEAofsmZnmc/mbG8AcV/
HrIVA8efnKMRJ6znQ7jZBlFfFzdJXztfyjFMigNANAxvx0lq2yabgqlpXy02PNU9
CmXjlxWX9jK+IiXX2bYxqfRaagwGf7vhOckc++We/Z3LJSycjmzSiwalFsDR4Bt2
K/q9E9oAtZXffUU7oMVnTvI6VbBC/sXkNNPfdUM1rKcWNO4cgEHIlNtmFrN1Eqz6
3BwQ9UC28JGHVKz01Qkq1xT9oPlnvUwlNGfRYYxqIiJc2f6FPCiJfgP0MCtoLHTO
CdCdo11eNAiAxBcc2LE9HcdJ37MHGwNnKavEVAi2nc5cw0VGXNH7kYKvGY/XcG9o
SqrRVdWXG8p3nkWR9YUo24eI0WibUigOQdn8YUzztXn3MGoO2RnYz7G78xOaGwJx
vNfL8NOMTuJxAgMBAAGjUzBRMB0GA1UdDgQWBBRT9Ear+TXUK/U9L6oXkzenKfhu
ZzAfBgNVHSMEGDAWgBRT9Ear+TXUK/U9L6oXkzenKfhuZzAPBgNVHRMBAf8EBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQClSUus4Rq7RQIPDx3n9OAhsLvYy/4NbxPh
pSaRDSo0yL6mVt/w7mze2vooi5PrOrh8TlqonKmMZx6Y5scgD5J/AMLZZ4QByYQe
yXktThUnQOrguFKEDnqfXm8bBgsycEk769Rsy4mz48D4nghvv4sFA/U3XSxt5T2E
J2HCr7G7lxJQ5NUF6+BdV2pndKfDaow/tweRSk/0/TwBrUJdB9rjh7tEbguRSkrr
Z8MSnEANHGmYZMBqytI/dPMT2CPETHc0WwTgS1PXds+cbibdOH6Wde7m91+Tx0DE
ufFlcBwRAYxk3GxVucH/BHRebgqQXNo9T0r501+tztI8ZorD5CBKl3EZsL36/Dvj
THbMnLw74bVYTfUUkM5O2blU2agkv8XIGXFyXBG8ty3H6IZ60Hv0jDQzz7Ddeb2t
LLGi8N8gHql7SWcMCP/qUhjoCTQ153WNj93ck+xQSHFPwAgiFEnf76xEVzlgu2ZA
FgSh9/CjySk5Tt0qgm4QwvSJBdNRcOrJg+cyoo6ZyhmMOEUPHiDjSbTekEItzSyV
63mQNt4RFaNjKOv3AiU4si+Apa2Zxh1suxBCw1tkhYbPS0s9yXEU1v0xFb8WuqaU
R3gV3qUEOiFZL/TWfCiqBkyLYjZkkPqpeE+xd+sUG/gUhIGOgzHuYKZzf/HV2k2Q
6s9Wbc79AQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
taC8Io6ZLxtXGjsosVFUsVWe+ejg+s0=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF0zCCA7ugAwIBAgIUOInSbC4+9Dq7DIB6VhXsqihsF5kwDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCQkUxETAPBgNVBAgMCFdpamdtYWFsMREwDwYDVQQHDAhX
aWpnbWFhbDETMBEGA1UECgwKU29mdEF0SG9tZTELMAkGA1UECwwCSVQxITAfBgNV
BAMMGExDTV9URVNUX1JPT1RfQ0FfU0VSVkVSMTAgFw0yNjAzMjkyMDI2MjBaGA8y
MTI2MDMwNTIwMjYyMFoweDELMAkGA1UEBhMCQkUxETAPBgNVBAgMCFdpamdtYWFs
MREwDwYDVQQHDAhXaWpnbWFhbDETMBEGA1UECgwKU29mdEF0SG9tZTELMAkGA1UE
CwwCSVQxITAfBgNVBAMMGExDTV9URVNUX1JPT1RfQ0FfU0VSVkVSMTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ/JA9ZL60xqX1IwSqKczodRqJx469IW
CIr0Vd9EHXSItBEua9g55NHeyDJt2oqXWQcoyezJ/3NrRQXA/qkVctil66/q8KS4
fDRnHpxq4KtaTqM0Er6+/QHASFp2vhd9scaPvKPmj3RV78i5pT4x7moLepfIk6YM
pe3LJhJmcfKFWdzXOj8GccrOaIlgAS3JopETf/e0wAkHEbyzMrFb6+6wZDaVzfmO
5ThEmxlbMc1jsHUG87MwgEvSjNewzzM3EbRFcLd/NP+z7lqzQo4cAE0Xg8ktekDH
5FssZzZQPU2PDL6OO0/fZf32P2968WCSmMeHLcIehcnG/NTE0HR+p8yqnBTL62Ki
7p3zOIMPBcY9iXLUAPYHHYaUy99aeHU6ADFC89QccMt2Q2cbWfSnahUpm27CHK+o
1Lgl4IPmfn5qdBCIu+74r6hvNiLFYmDnpBntjFUKQdF+Y3A4SjYSawt+gppaLwAC
SnlXdcO7evas9QnVYkBOPFGXiznt1jtVvqqvjOuZDZf8kRWZouA8nUPRsfXd9+k6
X8IAwLC9QmJTRcFFC6D/dVNyJE31DbGwwyRUJFV3m62/yJYpC3uZjoDg7E1Zcr22
17zhd1uw2BNoyIlAZ6RYcLg+KC25i/04MB8e2/VJ8bLr6tzrikoOLZVCq2wQXGDe
TJXPFd0ZQpfhAgMBAAGjUzBRMB0GA1UdDgQWBBQRYs+BanMXQuhM6A1yrctnBEBv
mDAfBgNVHSMEGDAWgBQRYs+BanMXQuhM6A1yrctnBEBvmDAPBgNVHRMBAf8EBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQA8dbR3/haQ2oNiOwseJQRhJFEJ6aW3/75d
DmxGiQiUW0MLU2RiT53zx74ZZ4N6Oxpa1XWyWQWFV7xECXJCeusUX+cxlxaee1yF
DhzCiTz88GO/Lw0uJfIdLVUkIQ3O6XtAa7xQE9MRYY4X28a0jkAnyQ+nDjGJ488D
sGZTZDn8Px/NTLSJEjfT3k1AriCm3TpE6UBfO34Y1p1azP0RuV5Fr+t4HYehGezA
ZmtWXMymE5/HbBMPXaosh4LPG9J6seauiDu4z7EVn1mvZ27rjSceR4sADnSckWLh
ebNhVxmHAdT/kE+YiCJX6D8ixfNwGh+zId577Tgttcu7kYhRt3fIHSZUSZnZ+i+4
T9EakAUXD/qF9RP/v5BlOVsL81uHPMeN5MjOFeP/JMMHnxoZBj+zTxCmUOWZ/zl1
DYGDIMTyu3X5/SeHT829WqcsdxaCgWEv46QWYpORj+JAlm0lp33c+3x3fh+GYkK1
M/H6B9CfyNjQSgOn9HMmgmXYv8K0bPm9usb0oOb3ltgZAw9uF1Gi7PeaWHQw0CXu
HWzJ4o4RhsjjUgpPzTFTpGGhZ5+aAuzqPQ98OoYnN0LepguhayPiO+BsDr890VlW
9qt0IlgvxVR+wVZcyYM9HY0BkBNu7PIYUg2ikEaOKdqp7OwnX1jkomOcLXnuFsbn
stjl14zStg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
BcgK0z/p4qmpvRK/prB5z6XgAjVZ
-----END PRIVATE KEY-----

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
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
b0nLdv8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
Z4TE6xSHrhRhBJc7eL8PxrCp6uHalA==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,252 @@
#!/bin/sh
# Wrapper around pkcs11-tool that suppresses all stderr output.
# Usage: pkcs11_tool_silent [pkcs11-tool arguments]
pkcs11_tool_silent() {
pkcs11-tool "$@" 2>/dev/null
}
# Wrapper around softhsm2-util that suppresses all stderr output.
# Usage: softhsm2_util_silent [softhsm2-util arguments]
softhsm2_util_silent() {
softhsm2-util "$@" 2>/dev/null
}
# Initialises the SoftHSM2 Hardware Security Module (HSM) environment by:
# - Creating a PKCS#11 token labelled "lcm_token" with PIN 12345
# - Generating a 2048-bit RSA key pair inside the token
# - Generating a Certificate Signing Request (CSR) for the client certificate
# using the OpenSSL PKCS#11 engine, with subject CN=client_cert
# Outputs progress messages for each step (success or failure).
# No arguments required; all configuration values are hardcoded.
configure_hsm() {
KEY_URI="pkcs11:token=lcm_token;object=key;type=private;pin-value=12345"
TOKEN_ACCESS="--module /usr/lib/softhsm/libsofthsm2.so --token-label lcm_token --login --pin 12345"
ROOT_LOCATION="/tmp/lcm_root_ca"
CLIENT_CERT_NAME="lcm_cert_client"
CLIENT_CERT_LOCATION="/etc/config/autocert/"
# Create a token
softhsm2_util_silent --init-token --free --label "lcm_token" --so-pin=12345 --pin=12345 > /dev/null && \
echo "Token created" || \
echo "Token creation failed"
# Generate a key in the token
# shellcheck disable=SC2086
pkcs11_tool_silent ${TOKEN_ACCESS} --keypairgen --key-type rsa:2048 --id 01 --label key >/dev/null && \
echo "Private key created" || \
echo "Private key creation failed"
# Generate a CSR
openssl req -new -engine pkcs11 -keyform engine -key "${KEY_URI}" -subj "/C=BE/ST=Brabant/L=Wijgmaal/O=SoftAtHome/OU=IT/CN=client_cert" -out "/tmp/${CLIENT_CERT_NAME}.csr" > /dev/null 2>&1
if [ ! -f /tmp/${CLIENT_CERT_NAME}.csr ]; then
echo "Failed to generate the CSR"
else
echo "CSR generated"
fi
}
# Configures the security environment for the LCM (Life Cycle Management) stack by:
# - Stopping and restarting the services: timingila, rlyeh, tr181-security
# - Installing the software modules ODL config and the GPG public signing key for rlyeh
# - Linking the client certificate and its PKCS#11 private key URI in the device data model
# (Device.Security.Certificate) via CLI JSON commands
# - Appending two signature server hostnames to /etc/hosts for local DNS resolution
# No arguments required; relies on the CLI_JSON environment variable being set.
configure_security() {
exec >/dev/null 2>&1
destination="$1"
/etc/init.d/timingila stop
/etc/init.d/rlyeh stop
/etc/init.d/tr181-security stop
sleep 2
mv /tmp/softwaremodules_default.odl /etc/config/softwaremodules/odl/timingila.odl
mkdir -p /usr/share/rlyeh/keys/
mv /tmp/sign_test_pub.asc /usr/share/rlyeh/keys/
/etc/init.d/rlyeh start
/etc/init.d/tr181-security start
sleep 2
/etc/init.d/timingila start
${CLI_JSON} 'Device.Security.Certificate.[CAFileName=="lcm_cert_client.crt"].PrivateKeyURI="pkcs11:token=lcm_token;object=key;type=private;pin-value=12345"'
${CLI_JSON} 'Device.Security.Certificate.[CAFileName=="lcm_cert_client.crt"].CertificateURI="file:///etc/config/autocert/lcm_cert_client.crt"'
# Set the defined server names in /etc/hosts
echo "${destination} signature.server1.local.com" >> /etc/hosts
echo "${destination} signature.server2.local.com" >> /etc/hosts
}
# Filters and formats a captured USP event from /tmp/captured_event.
# Extracts only the relevant fields: FaultCode, FaultString, CurrentState,
# and OperationPerformed, then sorts them, and strips leading/trailing
# whitespace and trailing commas.
# No arguments required; reads directly from /tmp/captured_event.
filtered_event() {
grep -E "FaultCode|FaultString|CurrentState|OperationPerformed" /tmp/captured_event | sort | sed 's/^[ \t]*//; s/,$//'
}
# Cleans up (silently) all security-related configuration and generated files by:
# - Removing previous subscription and used cli
# - Stopping the timingila and tr181-security services
# - Removing the client CSR, server CA certificate, client certificate,
# root CA directory, software modules ODL config, and the CRAM LCM ODL extension
# - Restarting the timingila and tr181-security services
# No arguments required; all paths are hardcoded.
cleanup_security() {
exec >/dev/null 2>&1
configure_datamodel remove_subscription
rm -rf /etc/amx/cli/usp-test-cli.* /usr/bin/usp-test-cli /tmp/event.lua
ROOT_LOCATION="/tmp/lcm_root_ca"
CLIENT_CERT_LOCATION="/etc/config/autocert/"
CLIENT_CERT_NAME="lcm_cert_client"
service timingila stop
service tr181-security stop
# Remove all config installed or generated
rm -rf /tmp/"${CLIENT_CERT_NAME}".csr
rm -rf /usr/share/ca-certificates/server_1.crt
rm -rf ${CLIENT_CERT_LOCATION}/${CLIENT_CERT_NAME}.crt
rm -rf ${ROOT_LOCATION}
rm -rf /etc/config/softwaremodules/odl/timingila.odl
rm -rf /etc/amx/tr181-security/extensions/01_cram_lcm.odl
sed -i '/signature\.server1\.local\.com/d' /etc/hosts
sed -i '/signature\.server2\.local\.com/d' /etc/hosts
# Delete the test HSM token
softhsm2-util --delete-token --token lcm_token
#rm -f /tmp/script_functions.sh /tmp/security_functions.sh
service tr181-security start
service timingila start
}
# Applies a named data model configuration command via usp-test-cli or ubus.
# Accepts a single command name and maps it to the appropriate data model
# parameter, value, and CLI interface. Supported commands:
# set_http - Set DU signature protocol to HTTP
# set_https - Set DU signature protocol to HTTPS
# set_useragent - Set a custom Rlyeh User-Agent string
# docker_repo_root_ca1 - Assign root_ca1 CA bundle to the docker repository
# docker_repo_ca_bundle- Assign ca_bundle CA bundle to the docker repository
# no_client_cert - Clear the client certificate for the mtls repository
# set_client_cert - Assign a client certificate (by serial number) to the mtls repository
# disable_docker_repo - Disable the docker repository
# set_default_ca_wrong - Set an incorrect default CA bundle on SoftwareModules config
# set_subscription - Create a DUStateChange event subscription via USP
# remove_subscription - Remove the DUStateChange event subscription via USP
# Usage: configure_datamodel <command>
# Returns 1 for unknown commands.
configure_datamodel() {
cmd="$1"
# Initialize variables
param=""
value=""
sub=""
cli=""
type=""
case "$cmd" in
set_subscription|remove_subscription)
type="sub"
;;
*)
type="set"
;;
esac
# Process commands
case "$cmd" in
set_http)
param='Device.SoftwareModules.Config.DUSignatureProtocols'
value='HTTP'
cli='usp'
;;
set_https)
param='Device.SoftwareModules.Config.DUSignatureProtocols'
value='HTTPS'
cli='usp'
;;
set_useragent)
param='Rlyeh.UserAgent'
value='my custom User-Agent value'
cli='ubus'
;;
docker_repo_root_ca1)
param='Device.SoftwareModules.Config.Repository.[Name == "docker_repo"].CABundle'
value='Device.Security.CABundle.[Name == "root_ca1"]'
cli='usp'
;;
docker_repo_ca_bundle)
param='Device.SoftwareModules.Config.Repository.[Name == "docker_repo"].CABundle'
value='Device.Security.CABundle.[Name == "ca_bundle"]'
cli='usp'
;;
no_client_cert)
param='Device.SoftwareModules.Config.Repository.[Name == "mtls"].Certificate'
value=''
cli='usp'
;;
set_client_cert)
param='Device.SoftwareModules.Config.Repository.[Name == "mtls"].Certificate'
value='Device.Security.Certificate.[SerialNumber == "0123456789"].'
cli='usp'
;;
disable_docker_repo)
param='Device.SoftwareModules.Config.Repository.[Name == "docker_repo"].Enable'
value='0'
cli='usp'
;;
set_default_ca_wrong)
param='Device.SoftwareModules.Config.CABundle'
value='Device.Security.CABundle.[Name == "root_ca1"]'
cli='usp'
;;
set_subscription)
sub='Device.LocalAgent.Subscription.+{Alias="DUStateChange", ID="DUStateChange", ReferenceList="Device.SoftwareModules.DUStateChange!", Enable=1, NotifType="Event"}'
cli='usp'
;;
remove_subscription)
sub='Device.LocalAgent.Subscription.[ Alias== "DUStateChange" ].-'
cli='usp'
;;
*)
echo "Unknown command: $cmd" >&2
return 1
;;
esac
# Execute based on cli and type
if [ "$cli" = "usp" ] && [ "$type" = "set" ]; then
usp-test-cli -lj "$param='$value'" | sed '/^$/d'
elif [ "$cli" = "ubus" ] && [ "$type" = "set" ]; then
ubus-cli -lj "$param='$value'" | sed '/^$/d'
elif [ "$cli" = "usp" ] && [ "$type" = "sub" ]; then
usp-test-cli "$sub"
fi
}
# Starts a background Lua listener for DUStateChange events on the
# Device.SoftwareModules data model path, writing output to a destination file.
# Usage: listen_dustatechange [destination]
# destination - (optional) file path to capture the event output.
# Defaults to /tmp/captured_event if not provided.
# The listener runs as a background process via event.lua.
listen_dustatechange() {
exec >/dev/null 2>&1
destination="$1"
if [ -z "$destination" ]; then
destination="/tmp/captured_event"
fi
lua /tmp/event.lua "Device.SoftwareModules." "DUStateChange!" > "$destination" &
}

View File

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEfDCCAmQCFBC9mlgxdM7X6UKAh+XxyWCYQSTaMA0GCSqGSIb3DQEBCwUAMHgx
CzAJBgNVBAYTAkJFMREwDwYDVQQIDAhXaWpnbWFhbDERMA8GA1UEBwwIV2lqZ21h
YWwxEzARBgNVBAoMClNvZnRBdEhvbWUxCzAJBgNVBAsMAklUMSEwHwYDVQQDDBhM
Q01fVEVTVF9ST09UX0NBX1NFUlZFUjEwIBcNMjYwMzI5MjAyNjQzWhgPMjEyNjAz
MDUyMDI2NDNaMHsxCzAJBgNVBAYTAkJFMREwDwYDVQQIDAhXaWpnbWFhbDERMA8G
A1UEBwwIV2lqZ21hYWwxEzARBgNVBAoMClNvZnRBdEhvbWUxCzAJBgNVBAsMAklU
MSQwIgYDVQQDDBtzaWduYXR1cmUuc2VydmVyMS5sb2NhbC5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQClC6tGBLMqCwyh0tVIGKNasJ1viubGyrmJ
a4eZb3hSSTGYk11yTVGmGeo4t2qlraVUGLpGRd/O9LzRWDWmCWzJdEj1gK4RdUpP
3+IWwgSYK9Uth5/4n/s7DPmHHETTtF/c5pGZ1RwpnIr7vK/oFaNaL5XyxvrqbszZ
tkjL9ETZKgWPxgt+z+J0bHKnw61wvInIsFATs1hJfiJYEx2Rt1GhmP17CL2qMYjJ
clRJpWCzzMEZJRqtv62fP1iazki/JVecr7guQYNoYh3XDglLaP6EdFqIJthM7jdu
litGT5vhf4ZR1rKhwRQcNiITcGtMl4BwNNcB+OyqdmDhW180TnxdAgMBAAEwDQYJ
KoZIhvcNAQELBQADggIBACwYEZe/PXwfse7jGVrDL/uGAcHnhQ5x/rqTLOLZ9ckz
Gc0b1ZnVemMqw7HkmIEJ/54ZO8DqozT6DNOpN/5TwS6UMlo7QB3Isma6ysZ18fq6
MY32F3HEGF2ICcpcm8qrgs31POaFzxNE/pTVauKmTz4nJ/xduuvDNN8AeysfmIZw
wzvDpRovrF5KngFXPJzG4+RP+k1OgYL2QqHUTvodmPYjgPFR1VcD3jrOGSxIRL8u
KR4HJYF12e7ww037t5boFdd01WMoWN5xe2Y6xnsOj9VzZd9bmPfKCEtwEf0bKgyL
u20BMfOaWZkZ7egC+MnaKNJKdIAie7rma3i2V9Zz9HjQn/9zJR164AFuV2XzZ/GC
aIL4uHhPC14XcyCUwwQisg9Wwr5443CxslVZr1Tugnz+MONUmQ2+smG8mGLWbig8
PgcutIn2VjoUaYy4oT2Rxsk+EleQl/WNwEaqmjChk3xi4bTye3rQRNO1KmRCKNSz
f725hxEpjrzdwbI/kvaXqHKjVLZBTMlSt8HvV8Ko2iqzs72TPYzF5QImeV4CGFSk
azgNbjb3KDxK9ixOo7HtWb24Asn+B0uFNdrGQdtuoB2YWRDcLs2Q3VNo+suZVpxN
XSuGleT/RG0YxNNyh1My7sVx+p7YQb6CE5P85/KVR4aapzKNjR3t0SwbF+/DWJ6C
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClC6tGBLMqCwyh
0tVIGKNasJ1viubGyrmJa4eZb3hSSTGYk11yTVGmGeo4t2qlraVUGLpGRd/O9LzR
WDWmCWzJdEj1gK4RdUpP3+IWwgSYK9Uth5/4n/s7DPmHHETTtF/c5pGZ1RwpnIr7
vK/oFaNaL5XyxvrqbszZtkjL9ETZKgWPxgt+z+J0bHKnw61wvInIsFATs1hJfiJY
Ex2Rt1GhmP17CL2qMYjJclRJpWCzzMEZJRqtv62fP1iazki/JVecr7guQYNoYh3X
DglLaP6EdFqIJthM7jdulitGT5vhf4ZR1rKhwRQcNiITcGtMl4BwNNcB+OyqdmDh
W180TnxdAgMBAAECggEAUKH80T5mkbnIOB8a2BhBZoM2x1HjIWfVcU+5dbrB2+Gq
e1Izqy4fH7k1dvQVBFBrn0RdbQuiJifnP5eKzk14eot3QYnWgOz+mztT565uNDHl
+lJyUzNFuDnEhr/G2G8dDn0O0UsOcT3roMU0Y3x+zAbHiU6xM2tiZVLrCcmTAUz+
5kImt38zE6xJbAvMpKruvIFF1X9rUT/rt6igdwrVywdO97u6NGH9zgyZ+eKMCsbn
Fbtw1fN0/z1jW3dUHJuwsuHqXQmY9C+czbAX0kYFPteDtjh49Mvvoi8vQ2NXCuly
00FLXCPwRSBOc+W/yFravD5+KRdnrix+EdpBsYkSeQKBgQC9/a7f6Z5pMG4rvcHO
OyRjU/peX72QrNgxg3jOu18DY+Z6FDtz8YvYYET+rANwMKRPV24TdxFqCxHlVSPP
BMhvN5AEimvsDMsmV31VL9Cn24BeF/fieQcaeWWalmQUZXSe1KUOmjZ28jphdCc5
nDBYd5CnlmRYOY+R7JPkeH9xpwKBgQDeY0bEhgjR6apIkxIIhsCIQuom7k0dt9bJ
GKAxEI7L2ff2Vipripdwit3sQ1vyjHDy3O1szy9BfpITr+OAt3AqoAu4D9aAt1uJ
SzxKe/lgMyARoN/kLfT9aBQbCWq33w4SlESZ5UtZqE7H9eAm2KnILSVfko3POjHq
jctmnlz6WwKBgQC4HJ8bo5P8UY9h2gh2pr9zdgz46YSVL7pt+P7YL6E6ctQFV5fp
mpivfVM/DEhkru57aLlmKYt5nPKhr6j806C8jjaE//Lnk9pF9KCjLavhDohOJqH0
GN62XBAHB1hCn7KsvFqbVPwUtlW23M2qOV5sTKmkjcv95wHnIkCLNe4inwKBgCkQ
4BKORbatlXpNXjkg2RDQenix7J+eQRVlbL9itVvDZlyg0LiHISvxGMX2MlZ5xKm0
TkuXfrxzaPolsrckKJxWbZORqSSft1GFCR8gAY7YIgXfVTjHm8Pnoj7T4FcP44Ne
ycQ5aU6nG9Uk/D1wKPoEDDC32WP49RrBEFxkxfqdAoGADj9wt40+h9jX3arUvtdw
rTKGrCZN225a8Y1G99aIiShoTDaOloWGx2mDsCkEpPz1H3DaoHlYlHZR6aQDsQQ3
Ga11TxbRM71Q7UwxbdtfJ2g+vuBtgtK8trM/sHBKye5r2poEYTerLcGIK0WKBGpd
1NbuJPpESL24sdhfkdOYPzA=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEfDCCAmQCFC3ixPlhaLwPh1trGTzQU55acBZeMA0GCSqGSIb3DQEBCwUAMHgx
CzAJBgNVBAYTAkJFMREwDwYDVQQIDAhXaWpnbWFhbDERMA8GA1UEBwwIV2lqZ21h
YWwxEzARBgNVBAoMClNvZnRBdEhvbWUxCzAJBgNVBAsMAklUMSEwHwYDVQQDDBhM
Q01fVEVTVF9ST09UX0NBX1NFUlZFUjEwIBcNMjYwMzI5MjAyNjQzWhgPMjEyNjAz
MDUyMDI2NDNaMHsxCzAJBgNVBAYTAkJFMREwDwYDVQQIDAhXaWpnbWFhbDERMA8G
A1UEBwwIV2lqZ21hYWwxEzARBgNVBAoMClNvZnRBdEhvbWUxCzAJBgNVBAsMAklU
MSQwIgYDVQQDDBtzaWduYXR1cmUuc2VydmVyMi5sb2NhbC5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDe7c57SBahRmy2Iz9ibQDL5grxGrz0SEWx
R+pBcbtzfd406m9XPWLbnk1q7cwu34TShsyRPulOYQSy2v+Wi1Jla1LxMI/7d4JJ
5Vx+tgDKi0X9C6zHCSiUcut4doLgPieffsPhbqVYPv21nEONdDkQroM9bjdFecZ3
ZXmC60nNZK4iHlhFUVUoUrlHAfTkRjUK8pI0fXk2l84rnK0XJdQ2rjdtXGjg3+M2
gP5yKoVxiHA3bRUUC+m2+RifoOLc0WjX47OaEYUyT7FKc88P9jcmJhJV4g6WpabK
A+0Z//Ffpz58dhCe8YPdh5OUmiOIMJTstaRyJE+CSDXErYW77U6vAgMBAAEwDQYJ
KoZIhvcNAQELBQADggIBAI52GBoGtiKv+OMRn96VVSYdIpM4B6R00VjHkdVeif1Z
Q98aJR4v/yrHn3MIbM2Ia40LugrBPb7brBAPE4GHywMqOK8wwCwTCWnmGGXnTpJ4
hNycMo7DtBGFj3QoUN7XIbna20c3xoCy0ZASGXuwbCQjABiv+Z52LK0Pan14IrGi
VynfFdM1AdgLA/b7gODfbbHalIeyB0qFLCTk6cTpqOLYRhYqZ/TwNSsQgeibBBDp
5nWfF7nwnqi8QMyPHGFQqyYEC72Bryw+TO2y6XyI9AxQPRJAXdNq+zWWKkXVr7NZ
lCAe0CwiVOYLLlJVUmJOR+e20igNolS9jXA+SXLgUHCHk26GffL066QWJbOu6CAD
vIPL0JUR7X4Isvjei9wUbwHU9VVp1Z8MX992Z+JLbrNGrY+GYQqu/88Icl/0ju1N
0N0vSJRchRr5CvATthzNhGU7ACPTpiEGtSIgc+kkiM/LsedkCNlIwxyxFKEWJW7d
Yi+btSo2pIEH1+flI85x3BFf0NtCNHAPf8sCG7/X6N0WCJSf/Rt9lyeTrC7tZ+pq
rm7DjyT3+VwWdWltq1zKAPHOxYPS54FEnJvwZVhnGlFCsoRhfZHdvIzQd6gEh38f
mCjVsDR7Mj32vT6lF8McNkopDt7hlSZKpeRL4n4ss/8o39AC/j6vMxymVtUlqrbk
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDe7c57SBahRmy2
Iz9ibQDL5grxGrz0SEWxR+pBcbtzfd406m9XPWLbnk1q7cwu34TShsyRPulOYQSy
2v+Wi1Jla1LxMI/7d4JJ5Vx+tgDKi0X9C6zHCSiUcut4doLgPieffsPhbqVYPv21
nEONdDkQroM9bjdFecZ3ZXmC60nNZK4iHlhFUVUoUrlHAfTkRjUK8pI0fXk2l84r
nK0XJdQ2rjdtXGjg3+M2gP5yKoVxiHA3bRUUC+m2+RifoOLc0WjX47OaEYUyT7FK
c88P9jcmJhJV4g6WpabKA+0Z//Ffpz58dhCe8YPdh5OUmiOIMJTstaRyJE+CSDXE
rYW77U6vAgMBAAECggEANaQgJo7yjwzslKkHk+3pnqZ0ZI6L//Wx+1X0Gpo8wi37
vVzZvLKzKmg9dajRlEfJZIT2DU8HgYobwNOsY3OTuH6qHwoR4y7fBVvwtTajGxmH
Fjvsb5oXDx1V5o8Rr9aU3y54ALMIiyLhFoWKxas9HfP39VyjZQ7HwCwFIIjwIcEQ
ehfkVt0mnmznGLB/0vdOxy9QmUfhUnf9CmvOLm86TQeeHthZl1eD38HqqmJgA28f
SWK8XtbeTooTdTsKmrUeAyCUn3w7RR7ZXphhz/B0G8XtBakhW4AINb0LFklKrHw9
0elCq6j0yKtfl3Z8YbB2/yqn/s5kspkRdgVwjEJTDQKBgQDieKR1nlij1CM+c2eI
5loEjG80Vxs/Yv5lZKgrqPd/TsopIpwHd5IWGT6CSuYTOve0cenS3+iWOvKDqiOD
fJnVHQTaW4IEHhM/VzaXLV+R980Qho7wffMXlhbOVjI7P1RcX5fF5VHRWX+dRVam
g+FasgJ/882YFOdVaSptgwFRhQKBgQD7/uzazp9ygKZRyS30fKA2AXZPXcs/zZZy
SqvM8Dc7bC6VROQ76oYWsrAQmV/kIy4PeSXzRfu2jZvgbu9xSS+N0R4VZd14qgg+
yj6ZhLx0AUYW/mBGWrbdtqty6ndrwzUpheiElXof/J8xUHSfZ8sKR8o3Y+2T6nKt
Bkcb/lX7owKBgG3VZK1GZmbN82nOPmA+l1mtYiFYPXa4Y/h4oLbL83xikdjxWAqn
Csp847v85yhcaNWyiVwkC4EQhZ0lXqPeQh0BPeFIj/2/OEZ33Znj/32jWGizWY95
BfRibh0T4LirNha2pbzsQonthd6YSjXnr9t0iZHUg9lGCgt6PYFvD6yhAoGAD82m
8PnwSfADfjGNrj16lqh00Pli27d67eP87jdKX3GjYj0VyyQkEJxYKlJUDyydoN7K
IH2NEZ/D3MlYPtSGJPCuYE0pHH4dUkLAtkP6xZOm355IT2E1AqaIDgbiQmHVnasG
L/pn1EW1fhQ7nBuYQibKabrclWAonO093GWQ4t0CgYAk8XDxwSc4ihKvUGjIIZeB
D97uvKPftxKFXR3CSoGlUnpdgCZ+oQeaGe+84JfBgSVTWKNXZC5PlvrQPS/U/o8F
24fWxRnMaAfRLErs4QdnjT4vR8z7qXvrGxCKl8+PvKANXdqqkQjVCaLYRRUJl+TE
wlIiIi45rCfWnQ6CRYXx7g==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,18 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBGg+0/4BCAC17QnZORN4VeiL01XQFZDb7HBOLJ/HYA+TL89kVKf+HXbOI+or
F1E0AHMGZFtIja44KaBt+9XQx01XJevE1LVR3YnL0KHzpXN5n7PwLsNP2uWUq8fW
MeGfUhCHyVIJJer5Lhz3uzHisqBN4y2mOQdNkskGcjbkzAXZrRMKr8yHmuFTFb4u
TD2aBdT6wC9fVPbj3BtxReyii0V7NxS8e+ARYrNpeCglFzRTOM+MOuppijvqlSig
sWrfoc+J+HLq8sn620HT9q05cbHKuURdkFOrHQFKBfKKdN0wduA1X+nqG6sW1mU/
P6rK2JsokzDDwiDCXB0aSA/7XUhzN7K1uSONABEBAAG0MlRlc3Qgc2lnbmluZyBr
ZXkgPGxjbV90ZXN0X3NpZ25pbmdAc29mdGF0aG9tZS5jb20+iQFOBBMBCgA4FiEE
TKV/Yy76VX53m81JSLuXDdrTmdUFAmg+0/4CGwMFCwkIBwIGFQoJCAsCBBYCAwEC
HgECF4AACgkQSLuXDdrTmdUdAAgAlPj0yy/QMkYg6cNlF8VnJ38vbm+0dfl+J6Cq
INM9dqJtlWVDX0OkA0elmKIIjQUn5HfzPSZ7OjRiGoSH86+b/yhMCq8M9nNA1w+1
T5Aqv9yER6A2kuALGOIoPvC0cVNBbouNyZEVGyHkvutyDKpjg2Oa69LOJOM/Dbcu
U+8sJhx1IDqTWRWyKptWL8raGCwcgS58FA+rBSjJl8+A1EWf+pZ6SAk9dk2UEN6o
ZHJnD2keA1B0/p9HkbPZeM+qlYVhjH8WdhIftDllSOoFN74VZ6RpKxOBJJOfCTiO
KMG0M9tycPImMcXpapZv1uu1siqOFejc/Jy82oibk+vLuKIQaQ==
=iGhR
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -0,0 +1,148 @@
%populate {
object 'SoftwareModules' {
object 'Config' {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"ca_bundle\"]" {
userflags %upc;
}
parameter 'DUSignatureProtocols' = "HTTPS";
parameter 'Certificate' = "" {
userflags %upc;
}
object 'Repository' {
instance add(1, 'docker_repo', 'Name' = "docker_repo", 'Alias' = "docker_repo") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"ca_bundle\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "docker_repo" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "docker://registry.gitlab.com" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "docker_repo";
parameter 'Certificate' = "" {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Repository" {
userflags %upc_changed, %upc;
}
}
instance add(2, 'no_auth', 'Name' = "no_auth", 'Alias' = "no_auth") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"root_ca1\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "no_auth" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "https://signature.server1.local.com:5443" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "no_auth";
parameter 'Certificate' = "" {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Signature" {
userflags %upc_changed, %upc;
}
}
instance add(3, 'basic_auth', 'Name' = "basic_auth", 'Alias' = "basic_auth") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"root_ca1\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "basic_auth" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "https://signature.server1.local.com:6443" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "basic_auth";
parameter 'Certificate' = "" {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Signature" {
userflags %upc_changed, %upc;
}
}
instance add(4, 'token_auth', 'Name' = "token_auth", 'Alias' = "token_auth") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"root_ca1\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "token_auth" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "https://signature.server1.local.com:7443" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "token_auth";
parameter 'Certificate' = "" {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Signature" {
userflags %upc_changed, %upc;
}
}
instance add(5, 'mtls', 'Name' = "signature1_mtls", 'Alias' = "mtls") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"root_ca1\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "mtls" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "https://signature.server1.local.com:8443" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "mtls";
parameter 'Certificate' = "Device.Security.Certificate.[SerialNumber==\"0123456789\"]." {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Signature" {
userflags %upc_changed, %upc;
}
}
instance add(6, 'wrong_ca', 'Name' = "wrong_ca", 'Alias' = "wrong_ca") {
parameter 'CABundle' = "Device.Security.CABundle.[Name == \"root_ca1\"]" {
userflags %upc_changed, %upc;
}
parameter 'Enable' = true {
userflags %upc_changed, %upc;
}
parameter 'Name' = "wrong_ca" {
userflags %upc_changed, %upc;
}
parameter 'BaseURL' = "https://signature.server1.local.com:9443" {
userflags %upc_changed, %upc;
}
parameter 'Alias' = "wrong_ca";
parameter 'Certificate' = "" {
userflags %upc_changed, %upc;
}
parameter 'Type' = "Signature" {
userflags %upc_changed, %upc;
}
}
}
}
object 'ExecEnv' {
}
object 'DeploymentUnit' {
}
object 'ExecutionUnit' {
}
}
}