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
| Path | Description |
|---|---|
state.reported.temperature | Single sensor value |
state.reported | All reported state |
metadata.reported.temperature.timestamp | Last update time |
version | Shadow version number |
AWS Authentication
AWS IoT requires Signature Version 4. Options:
- IAM credentials - Use
aws4library to sign requests - Cognito Identity - For end-user device access
- 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
| Path | Description |
|---|---|
properties.reported.temperature | Single sensor value |
properties.reported | All reported properties |
properties.reported.$metadata.temperature.$lastUpdated | Last update time |
deviceId | Device 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:
binaryDatais 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).