Skip to main content

IoT Provider Patterns for L{CORE}

This document describes how to use the existing HTTP provider to attest IoT device data from cloud platforms.

Overview

L{CORE} supports Tier 3 (API-Verified) IoT attestation: verifying device data by attesting API responses from cloud IoT platforms. This uses Reclaim Protocol's existing HTTP provider infrastructure - no custom code required.

┌─────────────────────────────────────────────────────────────────┐
│ IoT Platform APIs │
│ AWS IoT Core │ Azure IoT Hub │ Google Cloud IoT │ ThingsBoard │
└───────────────────────────┬─────────────────────────────────────┘
│ HTTPS/TLS

┌─────────────────────────────────────────────────────────────────┐
│ L\{CORE\} Attestor (HTTP Provider) │
│ - TLS verification │
│ - JSON extraction via jsonPath │
│ - Response matching │
└───────────────────────────┬─────────────────────────────────────┘
│ Verified claims

┌─────────────────────────────────────────────────────────────────┐
│ Cartesi Rollup (Privacy Layer) │
│ - Attestation storage │
│ - Access control │
│ - Discovery buckets │
└─────────────────────────────────────────────────────────────────┘

AWS IoT Core

API Endpoint

GET https://data-ats.iot.{region}.amazonaws.com/things/{thingName}/shadow
GET https://data-ats.iot.{region}.amazonaws.com/things/{thingName}/shadow?name={shadowName}

Example: Attest Device Shadow

import { createClaimOnAttestor } from '@localecore/attestor-core'

const result = await createClaimOnAttestor({
name: 'http',
params: {
url: 'https://data-ats.iot.{{region}}.amazonaws.com/things/{{thingName}}/shadow',
method: 'GET',
paramValues: {
region: 'us-east-1',
thingName: 'temperature-sensor-001'
},
responseMatches: [
{ type: 'contains', value: '"state"' },
{ type: 'contains', value: '"reported"' }
],
responseRedactions: [
{ jsonPath: 'state.reported.temperature' },
{ jsonPath: 'state.reported.humidity' },
{ jsonPath: 'state.reported.timestamp' }
]
},
secretParams: {
headers: {
'Authorization': 'AWS4-HMAC-SHA256 Credential=AKIA.../...'
}
},
ownerPrivateKey: '0x...',
client: { url: 'wss://attestor.example.com/ws' }
})

Response Structure

{
"state": {
"reported": {
"temperature": 23.5,
"humidity": 45.2,
"batteryLevel": 87,
"timestamp": 1704067200
},
"desired": {
"reportingInterval": 300
}
},
"metadata": {
"reported": {
"temperature": { "timestamp": 1704067200 }
}
},
"version": 42,
"timestamp": 1704067200
}

jsonPath Examples

PathDescription
state.reported.temperatureSingle sensor value
state.reportedAll reported state
metadata.reported.temperature.timestampLast update time
versionShadow version number

AWS Authentication

AWS IoT requires Signature Version 4. Options:

  1. IAM credentials - Use aws4 library to sign requests
  2. Cognito Identity - For end-user device access
  3. IoT credentials provider - Role-based temporary credentials

Azure IoT Hub

API Endpoint

GET https://{iotHubName}.azure-devices.net/twins/{deviceId}?api-version=2021-04-12
GET https://{iotHubName}.azure-devices.net/twins/{deviceId}/modules/{moduleId}?api-version=2021-04-12

Example: Attest Device Twin

const result = await createClaimOnAttestor({
name: 'http',
params: {
url: 'https://{{iotHubName}}.azure-devices.net/twins/{{deviceId}}?api-version=2021-04-12',
method: 'GET',
paramValues: {
iotHubName: 'my-iot-hub',
deviceId: 'sensor-device-001'
},
responseMatches: [
{ type: 'contains', value: '"properties"' }
],
responseRedactions: [
{ jsonPath: 'properties.reported.temperature' },
{ jsonPath: 'properties.reported.humidity' },
{ jsonPath: 'properties.reported.$metadata.temperature.$lastUpdated' }
]
},
secretParams: {
headers: {
'Authorization': 'SharedAccessSignature sr=my-iot-hub.azure-devices.net&sig=...&se=...&skn=iothubowner'
}
},
ownerPrivateKey: '0x...',
client: { url: 'wss://attestor.example.com/ws' }
})

Response Structure

{
"deviceId": "sensor-device-001",
"etag": "AAAAAAAAAAE=",
"properties": {
"desired": {
"reportingInterval": 300,
"$metadata": { ... },
"$version": 5
},
"reported": {
"temperature": 23.5,
"humidity": 45.2,
"firmwareVersion": "1.2.3",
"$metadata": {
"temperature": {
"$lastUpdated": "2024-01-01T00:00:00Z"
}
},
"$version": 12
}
}
}

jsonPath Examples

PathDescription
properties.reported.temperatureSingle sensor value
properties.reportedAll reported properties
properties.reported.$metadata.temperature.$lastUpdatedLast update time
deviceIdDevice identifier

Azure Authentication

Generate SAS token:

import crypto from 'crypto'

function generateSasToken(resourceUri: string, signingKey: string, policyName: string, expiresInMins: number) {
const expires = Math.ceil(Date.now() / 1000) + expiresInMins * 60
const toSign = encodeURIComponent(resourceUri) + '\n' + expires
const signature = crypto.createHmac('sha256', Buffer.from(signingKey, 'base64'))
.update(toSign)
.digest('base64')
return `SharedAccessSignature sr=${encodeURIComponent(resourceUri)}&sig=${encodeURIComponent(signature)}&se=${expires}&skn=${policyName}`
}

Google Cloud IoT Core

Note: Google Cloud IoT Core was retired on August 16, 2023. This section is included for reference with legacy systems or alternative GCP IoT solutions.

API Endpoint

GET https://cloudiot.googleapis.com/v1/projects/{projectId}/locations/{region}/registries/{registryId}/devices/{deviceId}/states

Example: Attest Device State

const result = await createClaimOnAttestor({
name: 'http',
params: {
url: 'https://cloudiot.googleapis.com/v1/projects/{{projectId}}/locations/{{region}}/registries/{{registryId}}/devices/{{deviceId}}/states',
method: 'GET',
paramValues: {
projectId: 'my-gcp-project',
region: 'us-central1',
registryId: 'my-registry',
deviceId: 'sensor-001'
},
responseMatches: [
{ type: 'contains', value: '"deviceStates"' }
],
responseRedactions: [
{ jsonPath: 'deviceStates.0.binaryData' },
{ jsonPath: 'deviceStates.0.updateTime' }
]
},
secretParams: {
headers: {
'Authorization': 'Bearer ya29.a0AfH6SM...'
}
},
ownerPrivateKey: '0x...',
client: { url: 'wss://attestor.example.com/ws' }
})

Response Structure

{
"deviceStates": [
{
"updateTime": "2024-01-01T00:00:00Z",
"binaryData": "eyJ0ZW1wZXJhdHVyZSI6MjMuNX0="
}
]
}

Note: binaryData is base64-encoded. Decode to get actual sensor values.


ThingsBoard (Self-Hosted)

API Endpoint

GET https://{host}/api/plugins/telemetry/DEVICE/{deviceId}/values/timeseries?keys={keys}

Example: Attest Telemetry

const result = await createClaimOnAttestor({
name: 'http',
params: {
url: 'https://{{host}}/api/plugins/telemetry/DEVICE/{{deviceId}}/values/timeseries?keys=temperature,humidity',
method: 'GET',
paramValues: {
host: 'thingsboard.example.com',
deviceId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
},
responseMatches: [
{ type: 'contains', value: '"temperature"' }
],
responseRedactions: [
{ jsonPath: 'temperature.0.value' },
{ jsonPath: 'humidity.0.value' },
{ jsonPath: 'temperature.0.ts' }
]
},
secretParams: {
headers: {
'X-Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9...'
}
},
ownerPrivateKey: '0x...',
client: { url: 'wss://attestor.example.com/ws' }
})

Response Structure

{
"temperature": [
{ "ts": 1704067200000, "value": "23.5" }
],
"humidity": [
{ "ts": 1704067200000, "value": "45.2" }
]
}

Common Patterns

Extracting Multiple Sensor Values

responseRedactions: [
{ jsonPath: 'state.reported.temperature' },
{ jsonPath: 'state.reported.humidity' },
{ jsonPath: 'state.reported.pressure' },
{ jsonPath: 'state.reported.batteryLevel' }
]

Verifying Device Identity

responseMatches: [
// Ensure response contains expected device ID
{ type: 'contains', value: '"deviceId":"sensor-001"' },
// Ensure data is recent (match timestamp pattern)
{ type: 'regex', value: '"timestamp":\\s*17[0-9]{8}' }
]

Hashing Sensitive Device Data

responseRedactions: [
// Hash device serial number for privacy
{ jsonPath: 'device.serialNumber', hash: 'oprf' },
// Reveal sensor values normally
{ jsonPath: 'state.reported.temperature' }
]

Using Named Groups for Extraction

responseMatches: [
{
type: 'regex',
value: '"temperature":\\s*(?<temp>[0-9.]+)'
}
]
// Extracted parameter: { temp: "23.5" }

Limitations

What This Approach Can Do

  • Verify device data exists in cloud platform
  • Prove data came from authenticated API endpoint
  • Extract specific sensor values with TLS verification
  • Hide API credentials from attestor

What This Approach Cannot Do

  • Verify data originated from physical device (trusts platform)
  • Attest devices without cloud connectivity
  • Provide real-time streaming attestation
  • Verify device hardware integrity

Trust Model

Physical Device → [Trust Gap] → Cloud Platform → [Verified] → L\{CORE\} Attestor

The attestation proves the cloud platform returned this data. It does not prove the physical device generated this data. The cloud platform is trusted.


Future Work: Direct Device Attestation

For higher trust guarantees, future work could include:

Tier 1: TEE-Native Devices

Devices with hardware security (TPM, Secure Element, ARM TrustZone) that can generate attestations directly.

Tier 2: Gateway-Attested

Local gateway running in TEE aggregates data from constrained devices and attests batches.

These approaches would require modifications to Reclaim Protocol's attestor-core (not in scope for L{CORE} layer).


References