Phase 8: BYOD Certificate Renewal

Phase 8: BYOD Certificate Renewal

Identify the Device

# Check OUI for manufacturer
grep -i '9C:83:06' /usr/share/hwdata/oui.txt

# Check ISE failure reason
dsource d000 dev/network/ise
dc_query "
SELECT TIMESTAMP_TIMEZONE, CALLING_STATION_ID, USERNAME,
       AUTHENTICATION_METHOD, AUTHENTICATION_PROTOCOL,
       PASSED, FAILURE_REASON
FROM radius_authentications
WHERE CALLING_STATION_ID = '9C:83:06:CE:89:46'
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 5 ROWS ONLY
" | jq -r '.[] | "\(.TIMESTAMP_TIMEZONE)  \(.PASSED)  \(.FAILURE_REASON)"'
Failure code 12516
EAP-TLS failed SSL/TLS handshake because of an expired certificate in the client certificates chain

Unseal Vault (API from workstation — no SSH needed)

Unseal keys in dsec have embedded double quotes — .strip('"') is required. Must unseal before issuing certificates.

dsource d000 dev/vault

# Verify keys are set (safe — no values shown)
env | grep VAULT_UNSEAL | awk -F= '{printf "%-25s %s\n", $1, (length($2) > 0 ? "SET (" length($2) " chars)" : "EMPTY")}'

# Key 1 (progress: 1 of 2)
curl -sk -X PUT https://vault-01.inside.domusdigitalis.dev:8200/v1/sys/unseal -d "$(python3 <<'EOF'
import json, os
print(json.dumps({"key": os.environ["VAULT_UNSEAL_KEY_1"].strip('"')}))
EOF
)"

# Key 2 (sealed: false)
curl -sk -X PUT https://vault-01.inside.domusdigitalis.dev:8200/v1/sys/unseal -d "$(python3 <<'EOF'
import json, os
print(json.dumps({"key": os.environ["VAULT_UNSEAL_KEY_2"].strip('"')}))
EOF
)" | jq '{sealed, cluster_name}'

Verify BYOD Role Configuration

vault read pki_int/roles/domus-byod
Key fields
allowed_domains:    [byod.inside.domusdigitalis.dev]
allow_subdomains:   true
ext_key_usage:      [ClientAuth]
max_ttl:            2160h (90 days)
organization:       Domus Digitalis
ou:                 BYOD Mobile Devices
country:            US
province:           California
locality:           Los Angeles

Update BYOD Role (if fields are empty — one-time setup)

vault write pki_int/roles/domus-byod \
  allowed_domains="byod.inside.domusdigitalis.dev" \
  allow_subdomains=true \
  allow_ip_sans=true \
  organization="Domus Digitalis" \
  ou="BYOD Mobile Devices" \
  country="US" \
  province="California" \
  locality="Los Angeles" \
  street_address="Domus Digitalis Home Enterprise" \
  postal_code="90001" \
  key_type="rsa" \
  key_bits=2048 \
  client_flag=true \
  server_flag=true \
  email_protection_flag=true \
  enforce_hostnames=true \
  max_ttl="2160h" \
  ext_key_usage="ClientAuth" \
  key_usage="DigitalSignature,KeyEncipherment,KeyAgreement" \
  allowed_uri_sans="spiffe://domusdigitalis.dev/byod/*" \
  allowed_other_sans="1.3.6.1.4.1.311.20.2.3;utf8:*" \
  policy_identifiers="2.5.29.32.0" \
  require_cn=true \
  no_store=false

Issue BYOD Client Certificate

vault write pki_int/issue/domus-byod \
  common_name="zfold7-evanusmodestus.byod.inside.domusdigitalis.dev" \
  alt_names="zfold7.byod.inside.domusdigitalis.dev" \
  uri_sans="spiffe://domusdigitalis.dev/byod/zfold7-evanusmodestus" \
  ip_sans="10.50.40.132" \
  ttl="2160h" \
  -format=json > /dev/shm/zfold7-cert.json
  • Role: domus-byod — 90-day TTL, ClientAuth EKU, full X.509 identity

  • CN: <device>-<owner>.byod.inside.domusdigitalis.dev (required domain suffix)

  • SAN DNS: alternate short name for device

  • SAN URI: SPIFFE identity for service mesh compatibility

  • SAN IP: device’s DHCP address on IoT VLAN (optional, changes with lease)

  • Issued from workstation directly — Vault is network-accessible, no SSH required

Extract Components

jq -r '.data.certificate' /dev/shm/zfold7-cert.json > /dev/shm/zfold7.crt
jq -r '.data.private_key' /dev/shm/zfold7-cert.json > /dev/shm/zfold7.key
jq -r '.data.ca_chain[]' /dev/shm/zfold7-cert.json > /dev/shm/zfold7-chain.pem

Verify Before Bundling

openssl x509 -in /dev/shm/zfold7.crt -noout -subject -issuer -serial -dates -ext subjectAltName,extendedKeyUsage
Expected — full X.509 identity
subject=C=US, ST=California, L=Los Angeles, street=Domus Digitalis Home Enterprise, postalCode=90001, O=Domus Digitalis, OU=BYOD Mobile Devices, CN=zfold7-evanusmodestus.byod.inside.domusdigitalis.dev
issuer=CN=DOMUS-ISSUING-CA
serial=<serial from Vault>
notBefore=<today>
notAfter=<today + 90 days>
X509v3 Subject Alternative Name:
    DNS:zfold7-evanusmodestus.byod.inside.domusdigitalis.dev, DNS:zfold7.byod.inside.domusdigitalis.dev, IP Address:10.50.40.132, URI:spiffe://domusdigitalis.dev/byod/zfold7-evanusmodestus
X509v3 Extended Key Usage:
    TLS Web Server Authentication, TLS Web Client Authentication, E-mail Protection
Full cert inspection (all fields)
jq -r '.data.certificate' /dev/shm/zfold7-cert.json | openssl x509 -noout -text

Bundle as PKCS#12 (Android requires .p12 format)

openssl pkcs12 -export \
  -out /dev/shm/zfold7-evanusmodestus.p12 \
  -inkey /dev/shm/zfold7.key \
  -in /dev/shm/zfold7.crt \
  -certfile /dev/shm/zfold7-chain.pem \
  -name "Domus BYOD EAP-TLS"

Enter an export password when prompted — you’ll need it when installing on the device.

Store P12 Password in gopass

gopass insert v3/domains/d000/identity/byod/zfold7/p12-password

Transfer to Device

Option 1: USB Drive (sneakernet)

sudo mount /dev/sda1 /mnt
sudo cp /dev/shm/zfold7-evanusmodestus.p12 /mnt/
ls -lh /mnt/*.p12
sudo umount /mnt

Option 2: ADB Push

adb push /dev/shm/zfold7-evanusmodestus.p12 /sdcard/Download/

Option 3: Email to Self

Send the .p12 as attachment. Open on device, install when prompted.

Install on Android Device

  1. Settings → Security → More security settings → Install from device storage

  2. Select zfold7-evanusmodestus.p12

  3. Enter the export password

  4. Name the certificate: Domus BYOD EAP-TLS

  5. Usage: VPN and apps → WiFi

Configure WiFi Profile on Device

  1. Settings → Wi-Fi → Domus-Secure (or Domus-IoT)

  2. EAP method: TLS

  3. CA certificate: DOMUS-ROOT-CA (or "Do not validate" temporarily)

  4. User certificate: Domus BYOD EAP-TLS

  5. Identity: zfold7-evanusmodestus.byod.inside.domusdigitalis.dev

  6. Anonymous identity: (leave blank)

  7. Connect

The Identity field must match the certificate CN exactly. ISE’s authentication policy checks this against the certificate subject. A mismatch results in 12514 EAP-TLS failed.

Verify Authentication in ISE

DataConnect — Auth Records

dsource d000 dev/network/ise
dc_query "
SELECT TIMESTAMP_TIMEZONE, CALLING_STATION_ID, USERNAME,
       AUTHENTICATION_METHOD, AUTHENTICATION_PROTOCOL,
       PASSED, FAILURE_REASON, POLICY_SET_NAME
FROM radius_authentications
WHERE CALLING_STATION_ID = '9C:83:06:CE:89:46'
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 5 ROWS ONLY
" | jq -r '.[] | "\(.TIMESTAMP_TIMEZONE)  \(.PASSED)  \(.AUTHENTICATION_PROTOCOL)  \(.FAILURE_REASON)"' | column -t
Expected — EAP-TLS Pass, no failure reason
2026-06-08 ...  Pass  EAP-TLS  null

MnT — Active Session

mnt "/Session/ActiveList" | \
  xq -r '.activeList.activeSession[] | select(.calling_station_id=="9C:83:06:CE:89:46") |
"\(.calling_station_id)\t\(.user_name)\t\(.framed_ip_address)"' | column -t -s $'\t'

OUI + Endpoint Dashboard

# Verify all connected devices with manufacturer lookup
for mac in $(mnt "/Session/ActiveList" | xq -r '.activeList.activeSession[].calling_station_id'); do
  oui=$(echo $mac | awk -F: '{printf "%s:%s:%s", $1, $2, $3}')
  vendor=$(grep -i "${oui//:/-}" /usr/share/hwdata/oui.txt 2>/dev/null | head -1 | awk -F'\t' '{print $NF}')
  printf "%-20s %-8s %s\n" "$mac" "$oui" "${vendor:-unknown/randomized}"
done

Secure Cleanup

shred -vfz -n 3 /dev/shm/zfold7*
rm -f /dev/shm/zfold7*

Seal Vault (API from workstation — no SSH needed)

curl -sk -X PUT -H "X-Vault-Token: $(echo $VAULT_ROOT_TOKEN | tr -d '\"')" \
  https://vault-01.inside.domusdigitalis.dev:8200/v1/sys/seal
Verify sealed
curl -sk https://vault-01.inside.domusdigitalis.dev:8200/v1/sys/seal-status | jq '{sealed, cluster_name}'
Expected
{
  "sealed": true,
  "cluster_name": "vault-cluster-904d4b42"
}