From a2125a424e385592b171e474b8582a4b58278d99 Mon Sep 17 00:00:00 2001 From: TSainathPolisetty Date: Mon, 15 Dec 2025 13:41:14 -0500 Subject: [PATCH 1/2] prepare-device: Modify to add OpenSSL-based secure onboarding workflow Signed-off-by: TSainathPolisetty --- snap/hooks/prepare-device | 131 +++++++++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 17 deletions(-) diff --git a/snap/hooks/prepare-device b/snap/hooks/prepare-device index 2ee7f65..1c26327 100755 --- a/snap/hooks/prepare-device +++ b/snap/hooks/prepare-device @@ -1,23 +1,120 @@ -#!/bin/sh +# #!/bin/sh -# This file is included for reference purposes. If MODEL_APIKEY is not set -# in snapcraft.yaml (as is the default), it is a no-op. For more about how -# to use this script to connect a device to an IoT App Store, see -# - https://ubuntu.com/core/services/guide/serial-vault-overview -# - https://ubuntu.com/core/services/guide/connecting-devices -# - https://snapcraft.io/docs/gadget-snap#heading--prepare +# # This hook implements the device-side portions of the Ubuntu Core secure +# # onboarding flow. +# # +# # Responsibilities: +# # - Optionally configure the device-service endpoint and authentication +# # headers when MODEL_APIKEY is provided (e.g. for Serial Vault or a +# # private Brand Store). If MODEL_APIKEY is not set, this part is a no-op +# # and snapd defaults are used. +# # - Generate and persist a hardware identity keypair (RSA-2048) using +# # OpenSSL. The private key is stored in SNAP_SAVE_DATA and is generated +# # only once per device. +# # +# # This hook intentionally does NOT: +# # - Perform any network operations +# # - Contact the device service directly +# # - Sign request-ids or construct registration payloads +# # +# # Cryptographic proof of identity is handled later by the +# # prepare-serial-request hook, which signs the request-id issued by snapd +# # using the hardware identity private key generated here. +# # +# # This implementation follows the Ubuntu Core secure onboarding design +# # # # +# # The OpenSSL-based hardware identity is compatible with the standard +# # RSA-SHA256 verification performed by the Model / Device Service. -set -eu -if [ -z "$MODEL_APIKEY" ] ; then - exit 0 -fi -exec >> $SNAP_COMMON/prepare-device-hook.log 2>&1 +# set -eu -# If you are forking and building your own gadget: -# implement your preferred way of generating a serial number for this device here -snapctl set registration.proposed-serial="\"$(date -u)\"" +# TAG="prepare-device" -snapctl set device-service.url="https://serial-vault-partners.canonical.com/v1/" -snapctl set device-service.headers="{\"api-key\": \"$MODEL_APIKEY\"}" +# log_info() { +# printf "%s\n" "$1" | systemd-cat -t "$TAG" -p info +# } + +# log_error() { +# printf "%s\n" "$1" | systemd-cat -t "$TAG" -p err +# } + +# log_info "prepare-device: starting" + +# # ---------------------------------------------------------------------- +# # Resolve SNAP_DATA and SNAP_SAVE_DATA +# # ---------------------------------------------------------------------- +# if [ -z "${SNAP_DATA:-}" ]; then +# log_error "SNAP_DATA is not set" +# exit 1 +# fi + +# if [ -z "${SNAP_SAVE_DATA:-}" ]; then +# SNAP_SAVE_DATA="$SNAP_DATA" +# fi + +# LOG_FILE="$SNAP_DATA/prepare-device.log" + +# echo "prepare-device: started" >> "$LOG_FILE" +# echo "SNAP_DATA=$SNAP_DATA" >> "$LOG_FILE" +# echo "SNAP_SAVE_DATA=$SNAP_SAVE_DATA" >> "$LOG_FILE" + +# log_info "SNAP_DATA=$SNAP_DATA" +# log_info "SNAP_SAVE_DATA=$SNAP_SAVE_DATA" + +# mkdir -p "$SNAP_SAVE_DATA" + +# # ---------------------------------------------------------------------- +# # OPTIONAL: Device-service / API configuration +# # ---------------------------------------------------------------------- +# # This is a no-op unless MODEL_APIKEY is provided via snapcraft.yaml +# # ---------------------------------------------------------------------- + +# if [ -n "${MODEL_APIKEY:-}" ]; then +# log_info "MODEL_APIKEY provided — configuring device service" +# echo "MODEL_APIKEY provided" >> "$LOG_FILE" + +# # Proposed serial MUST be a JSON string +# snapctl set registration.proposed-serial="\"$(date -u)\"" + +# # Serial / model service endpoint +# snapctl set device-service.url="https://serial-vault-partners.canonical.com/v1/" + +# # API authentication header +# snapctl set device-service.headers="{\"api-key\":\"$MODEL_APIKEY\"}" +# else +# log_info "MODEL_APIKEY not set — skipping device-service configuration" +# echo "MODEL_APIKEY not set" >> "$LOG_FILE" +# fi + +# # ---------------------------------------------------------------------- +# # Generate hardware identity keypair (OpenSSL) +# # ---------------------------------------------------------------------- +# KEY_PRIV="$SNAP_SAVE_DATA/hardware-id" +# KEY_PUB="$SNAP_SAVE_DATA/hardware-id.pub" + +# if [ ! -f "$KEY_PRIV" ]; then +# log_info "Generating RSA-2048 hardware identity keypair" +# echo "Generating keypair at $KEY_PRIV" >> "$LOG_FILE" + +# if ! openssl genrsa -out "$KEY_PRIV" 2048 >/dev/null 2>&1; then +# log_error "Failed to generate private key" +# exit 1 +# fi + +# if ! openssl rsa -in "$KEY_PRIV" -pubout -out "$KEY_PUB" >/dev/null 2>&1; then +# log_error "Failed to extract public key" +# exit 1 +# fi + +# log_info "Keypair created" +# echo "Keypair created" >> "$LOG_FILE" +# else +# log_info "hardware-id keypair already exists" +# echo "hardware-id exists" >> "$LOG_FILE" +# fi + +# log_info "prepare-device: finished" +# echo "prepare-device: finished" >> "$LOG_FILE" +# exit 0 From 9b7a9089e20ed5302c127de15a781dc8e8759561 Mon Sep 17 00:00:00 2001 From: TSainathPolisetty Date: Mon, 15 Dec 2025 13:43:12 -0500 Subject: [PATCH 2/2] prepare-serial-request: Add the new hook for OpenSSL-based secure onboarding workflow (signing the nonce) Signed-off-by: TSainathPolisetty --- snap/hooks/prepare-device | 15 ++++ snap/hooks/prepare-serial-request | 142 ++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 snap/hooks/prepare-serial-request diff --git a/snap/hooks/prepare-device b/snap/hooks/prepare-device index 1c26327..4b95b48 100755 --- a/snap/hooks/prepare-device +++ b/snap/hooks/prepare-device @@ -1,3 +1,18 @@ +# NOTE: +# ----- +# This hook is intentionally commented out and provided for reference only. +# +# It documents an OpenSSL-based implementation of the device-side secure +# onboarding flow, but is NOT enabled by default. +# +# This avoids changing runtime behavior while making the reference +# implementation available for review, discussion, and future activation. +# +# To enable this hook, uncomment the script contents and ensure the hook +# is marked executable. + + + # #!/bin/sh # # This hook implements the device-side portions of the Ubuntu Core secure diff --git a/snap/hooks/prepare-serial-request b/snap/hooks/prepare-serial-request new file mode 100644 index 0000000..4a8275c --- /dev/null +++ b/snap/hooks/prepare-serial-request @@ -0,0 +1,142 @@ +# #!/bin/sh + +# # This hook implements the device-side step of the +# # Ubuntu Core secure onboarding flow. +# # +# # Responsibilities: +# # - Retrieve the request-id issued by snapd for device registration +# # - Sign the request-id using the persistent hardware identity private +# # key generated by the prepare-device hook +# # - Construct the registration request payload (registration.body) +# # expected by snapd and the Model / Device Service +# # +# # The registration payload contains: +# # - The hardware identity public key (base64-encoded PEM) +# # - The SHA256 fingerprint of the public key +# # - The RSA-SHA256 signature of the request-id +# # - The signature hash algorithm identifier +# # +# # This hook intentionally does NOT: +# # - Generate or manage hardware identity keys +# # - Perform any network operations +# # - Contact the device service directly +# # - Configure device-service endpoints or authentication +# # +# # Hardware identity generation and optional device-service configuration +# # are handled by the prepare-device hook. This hook is executed only after +# # snapd has obtained a request-id from the configured device service. +# # +# # The cryptographic operations are implemented using OpenSSL and produce +# # RSA-SHA256 signatures compatible with standard Model / Device Service +# # verification. +# # +# # This implementation follows the Ubuntu Core secure onboarding design +# # + + + +# set -eu + +# TAG="prepare-serial-request" + +# log_info() { +# printf "%s\n" "$1" | systemd-cat -t "$TAG" -p info +# } + +# log_error() { +# printf "%s\n" "$1" | systemd-cat -t "$TAG" -p err +# } + +# log_info "prepare-serial-request: starting" + +# # ---------------------------------------------------------------------- +# # Resolve SNAP_DATA + SNAP_SAVE_DATA +# # ---------------------------------------------------------------------- +# if [ -z "${SNAP_DATA:-}" ]; then +# log_error "SNAP_DATA is not set" +# exit 1 +# fi + +# if [ -z "${SNAP_SAVE_DATA:-}" ]; then +# SNAP_SAVE_DATA="$SNAP_DATA" +# fi + +# LOG_FILE="$SNAP_DATA/prepare-serial.log" +# echo "prepare-serial-request: started" >> "$LOG_FILE" + +# # ---------------------------------------------------------------------- +# # Get request-id +# # ---------------------------------------------------------------------- +# RID="$(snapctl get registration.request-id 2>/dev/null || true)" + +# if [ -z "$RID" ] && [ -f "$SNAP_DATA/request-id.txt" ]; then +# RID="$(cat "$SNAP_DATA/request-id.txt")" +# fi + +# RID="$(printf "%s" "$RID")" + +# if [ -z "$RID" ]; then +# log_error "No request-id" +# exit 1 +# fi + +# log_info "Using request-id: $RID" +# echo "request-id=$RID" >> "$LOG_FILE" + +# # ---------------------------------------------------------------------- +# # Key locations +# # ---------------------------------------------------------------------- +# KEY_PRIV="$SNAP_SAVE_DATA/hardware-id" +# KEY_PUB="$SNAP_SAVE_DATA/hardware-id.pub" + +# if [ ! -f "$KEY_PRIV" ]; then +# log_error "Missing hardware-id private key" +# exit 1 +# fi + +# # ---------------------------------------------------------------------- +# # Prepare working directory +# # ---------------------------------------------------------------------- +# WORK_DIR="$SNAP_SAVE_DATA/prepare-serial" +# mkdir -p "$WORK_DIR" + +# PAYLOAD="$WORK_DIR/request-id.txt" +# printf "%s" "$RID" > "$PAYLOAD" + +# # ---------------------------------------------------------------------- +# # Sign request-id +# # ---------------------------------------------------------------------- +# SIG_BIN="$WORK_DIR/sig.bin" +# SIG_B64="$WORK_DIR/sig.b64" + +# openssl dgst -sha256 -sign "$KEY_PRIV" -out "$SIG_BIN" "$PAYLOAD" +# base64 < "$SIG_BIN" | tr -d '\n' > "$SIG_B64" + +# # ---------------------------------------------------------------------- +# # Base64 public key +# # ---------------------------------------------------------------------- +# PUB_B64="$WORK_DIR/pub.b64" +# base64 < "$KEY_PUB" | tr -d '\n' > "$PUB_B64" + +# # ---------------------------------------------------------------------- +# # SHA256(pubkey) +# # ---------------------------------------------------------------------- +# PUB_SHA="$WORK_DIR/pub.sha256" +# openssl dgst -sha256 "$KEY_PUB" | awk '{print $2}' > "$PUB_SHA" + +# # ---------------------------------------------------------------------- +# # Construct JSON for snapd +# # ---------------------------------------------------------------------- +# OUT="$SNAP_DATA/registration.body" + +# printf \ +# '{"hardware-id-key":"%s","hardware-id-key-sha256":"%s","signature-hash-algorithm":"sha256","request-id-signature":"%s"}' \ +# "$(cat "$PUB_B64")" \ +# "$(cat "$PUB_SHA")" \ +# "$(cat "$SIG_B64")" \ +# > "$OUT" + +# log_info "registration.body written" +# echo "registration.body written to $OUT" >> "$LOG_FILE" + +# exit 0