1226  CoAP Security, Applications, and Implementation

1226.1 Security with DTLS

CoAP uses DTLS (Datagram TLS) for security:

Features: - Encryption of messages - Authentication (Pre-Shared Keys or Certificates) - Integrity protection

DTLS vs TLS: - TLS = for TCP (HTTP) - DTLS = for UDP (CoAP)

Port: - CoAP: 5683 - CoAPs (secure): 5684

1226.2 Real-World Applications

1226.2.1 Smart Energy

Smart Meters: - Read consumption (GET) - Update tariffs (PUT) - Control load (POST)

coap://meter.home/consumption
coap://meter.home/tariff
coap://meter.home/switch

1226.2.2 Building Automation

HVAC Control: - Read temperature - Set thermostat - Schedule modes

Lighting: - Query status - Control brightness - Manage groups (multicast)

1226.2.3 Industrial IoT

Sensor Networks: - Poll sensor values - Configure sampling rates - Firmware updates

Asset Tracking: - Location queries - Status updates - Alert notifications

1226.3 🧪 Lab Exercise

Goal: Build CoAP temperature monitoring system

Hardware (or simulate): - ESP32 board - DHT22 sensor

Tasks:

  1. Setup CoAP Server (on Raspberry Pi or PC):
    • Install aiocoap
    • Create temperature resource
    • Add humidity resource
    • Implement GET and PUT methods
  2. Create ESP32 CoAP Client:
    • Connect to Wi-Fi
    • Send GET requests every 30s
    • Display responses on Serial Monitor
  3. Add Observe Pattern:
    • Server notifies on temperature change
    • Client receives push updates
    • No polling needed
  4. Implement Multicast Discovery:
    • Client broadcasts to find servers
    • Servers respond with capabilities

Challenge: Add CoAP-to-MQTT bridge for cloud integration

1226.4 When to Use CoAP

1226.4.1 Choose CoAP when:

Constrained devices (8-bit MCU, limited RAM) ✅ Low power critical (battery-operated) ✅ Request/Response pattern fits your needs ✅ RESTful API desired ✅ Multicast needed for device discovery ✅ IPv6 networks (6LoWPAN) ✅ Direct device-to-device communication

1226.4.2 Choose HTTP when:

  • Web browser access needed
  • Infrastructure already HTTP-based
  • Devices not constrained
  • Complex authentication required

1226.4.3 Choose MQTT when:

  • Publish/Subscribe pattern needed
  • Central broker acceptable
  • Many-to-many communication
  • QoS levels important
  • Topic-based routing preferred

1226.5 Common Implementation Pitfalls

CautionPitfall: Forgetting to Handle CoAP Token Matching in Observe Responses

The Mistake: Implementing CoAP Observe without properly tracking tokens, causing clients to misattribute notifications to the wrong resources when observing multiple endpoints simultaneously.

Why It Happens: Developers familiar with HTTP assume response correlation is automatic. In CoAP, the token (0-8 bytes) links requests to responses. When observing /temperature and /humidity concurrently, both notification streams arrive on the same UDP socket and must be matched by token.

The Fix: Maintain a token-to-resource mapping for all active observations:

# BAD: Ignoring tokens
def on_notification(response):
    print(f"Got value: {response.payload}")  # Which resource?

# GOOD: Token-based dispatch
observations = {}  # token -> resource_uri mapping

def observe_resource(uri):
    token = generate_unique_token()
    observations[token] = uri
    send_observe_request(uri, token)

def on_notification(response):
    uri = observations.get(response.token)
    if uri:
        print(f"Resource {uri} = {response.payload}")
    else:
        print(f"Unknown token, sending RST")
        send_reset(response.mid)

Use unique tokens per observation (e.g., 4-byte random values) and clean up mappings when observations are cancelled or reset.

CautionPitfall: CoAP Retransmission Backoff Flooding the Network

The Mistake: Using aggressive fixed-interval retransmissions for CON messages instead of exponential backoff, causing network congestion when packet loss occurs.

Why It Happens: Developers implement simple “retry every 2 seconds” logic without realizing that CoAP specifies exponential backoff (RFC 7252). On a lossy wireless network with 20% packet loss, aggressive retries amplify traffic by 5x and worsen congestion.

The Fix: Implement RFC 7252 compliant retransmission with exponential backoff:

# BAD: Fixed interval retry (network flooding)
RETRY_INTERVAL = 2.0  # seconds
for attempt in range(MAX_RETRIES):
    send_message(msg)
    if wait_for_ack(RETRY_INTERVAL):
        break

# GOOD: Exponential backoff per RFC 7252
ACK_TIMEOUT = 2.0      # Initial timeout (2 seconds)
ACK_RANDOM_FACTOR = 1.5  # Randomization factor
MAX_RETRANSMIT = 4      # Maximum retries

def coap_transmit(msg):
    timeout = ACK_TIMEOUT * (1 + random.random() * (ACK_RANDOM_FACTOR - 1))
    for attempt in range(MAX_RETRANSMIT + 1):
        send_message(msg)
        if wait_for_ack(timeout):
            return True
        timeout *= 2  # Double timeout each retry: 2s, 4s, 8s, 16s
    return False  # Give up after ~45 seconds total

With proper backoff: first retry at 2-3s, second at 4-6s, third at 8-12s, fourth at 16-24s. Total worst-case wait: ~45 seconds before declaring failure.

1226.6 CoAP Implementation Patterns

Understanding CoAP implementation through message exchanges, resource patterns, and performance characteristics:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#E67E22', 'secondaryColor': '#16A085', 'tertiaryColor': '#7F8C8D'}}}%%
graph TB
    subgraph "CoAP Message Types"
        CON[Confirmable CON<br/>Requires ACK]
        NON[Non-Confirmable NON<br/>No ACK needed]
        ACK[Acknowledgment ACK<br/>Response to CON]
        RST[Reset RST<br/>Reject message]
    end

    subgraph "Resource Patterns"
        GET[GET /resource<br/>Read data]
        POST[POST /resource<br/>Create new]
        PUT[PUT /resource<br/>Update existing]
        DEL[DELETE /resource<br/>Remove]
    end

    subgraph "Observe Pattern"
        OBS1[Client: GET /temp<br/>Observe: 0]
        OBS2[Server: 2.05 Content<br/>Observe: 12]
        OBS3[Server: Notification<br/>Observe: 13]
        OBS4[Server: Notification<br/>Observe: 14]
    end

    CON --> GET & POST & PUT & DEL
    OBS1 --> OBS2 --> OBS3 --> OBS4

    style CON fill:#2C3E50,stroke:#16A085,color:#fff
    style NON fill:#16A085,stroke:#2C3E50,color:#fff
    style ACK fill:#E67E22,stroke:#2C3E50,color:#fff
    style RST fill:#7F8C8D,stroke:#2C3E50,color:#fff
    style GET fill:#2C3E50,stroke:#16A085,color:#fff
    style POST fill:#16A085,stroke:#2C3E50,color:#fff
    style PUT fill:#16A085,stroke:#2C3E50,color:#fff
    style DEL fill:#E67E22,stroke:#2C3E50,color:#fff

Figure 1226.1: CoAP Message Types, RESTful Methods, and Observe Pattern Overview
CoAP implementation involves message type selection, RESTful operations, and the Observe pattern for subscriptions

1226.6.1 CoAP vs HTTP vs MQTT: Performance Comparison

Overhead Analysis (20-byte temperature reading):

Protocol Header Size Total Bytes Overhead % Transport Latency
CoAP 4 bytes 24 bytes 16.7% UDP 50 ms
HTTP/1.1 ~200 bytes 220 bytes 90.9% TCP 200 ms
MQTT 2 bytes 22 bytes 9.1% TCP 150 ms

Energy Consumption (24 hours, readings every 30s):

Protocol Messages/Day Energy/Message Total Energy Battery Life Impact
CoAP 2,880 153 mJ 441 mWh Baseline (100%)
HTTP 2,880 190 mJ 547 mWh -24% battery life
MQTT 2,880 163 mJ 468 mWh -6% battery life
NotePractical CoAP Implementation Resources

Official Libraries and Tools:

Platform Library Installation Documentation
Python aiocoap pip install aiocoap aiocoap.readthedocs.io
Arduino/ESP32 CoAP Simple Library Arduino Library Manager GitHub: coap-simple
Node.js coap npm install coap npmjs.com/package/coap
Java Eclipse Californium Maven dependency eclipse.org/californium
C/C++ libcoap System package libcoap.net

Testing and Debugging Tools:

  • coap-client (libcoap): Command-line CoAP client for testing

    # GET request
    coap-client -m get coap://localhost/temperature
    
    # POST with payload
    coap-client -m post coap://localhost/sensor -e "22.5"
    
    # Observe resource
    coap-client -m get -s 60 coap://localhost/temperature
  • Copper (Cu): Firefox/Chrome plugin for CoAP browsing (deprecated but useful for learning)

  • Wireshark: CoAP dissector included (filter: coap)

  • nRF Connect CoAP: Mobile app for testing CoAP servers

Example Implementation Patterns:

Pattern 1: Sensor Reading (NON message)

Sensor → Gateway:  CON GET /temperature
Gateway → Sensor:  ACK 2.05 Content
                   Payload: 22.5°C

Overhead: 2 messages, ~50 bytes total
Latency: 1 RTT (~20-50ms on local network)
Reliability: Guaranteed (CON requires ACK)

Pattern 2: Frequent Updates (Observe)

Client → Server:   CON GET /temperature, Observe: 0
Server → Client:   ACK 2.05 Content, Observe: 12
                   Initial value: 22.5°C

[30 seconds later]
Server → Client:   CON 2.05 Content, Observe: 13
                   Updated value: 23.1°C

[30 seconds later]
Server → Client:   CON 2.05 Content, Observe: 14
                   Updated value: 22.9°C

Overhead: 1 subscribe + N notifications
Battery savings: Avoid polling every 30s

Pattern 3: Multicast Discovery

Client → FF02::FD: NON GET /.well-known/core
Device1 → Client:  NON 2.05 Content
                   </temperature>,</humidity>
Device2 → Client:  NON 2.05 Content
                   </pressure>,</light>

Use case: Discover all CoAP devices on local network
Result: List of available resources from all devices

1226.6.2 CoAP Response Code Categories

Category Code Range Meaning Example Use Cases
Success (2.xx) 2.01-2.05 Request succeeded 2.05 Content (GET success), 2.04 Changed (PUT success)
Client Error (4.xx) 4.00-4.15 Client made error 4.04 Not Found (bad URI), 4.01 Unauthorized (auth required)
Server Error (5.xx) 5.00-5.05 Server failed 5.00 Internal Server Error, 5.03 Service Unavailable

Common Response Codes:

  • 2.01 Created: Resource successfully created (POST)
  • 2.04 Changed: Resource updated (PUT)
  • 2.05 Content: Resource data returned (GET)
  • 4.04 Not Found: Resource doesn’t exist
  • 4.05 Method Not Allowed: Operation not supported
  • 5.00 Internal Server Error: Server processing failed

1226.6.3 Hands-On Learning Resources

Interactive Tutorials: 1. Eclipse Californium CoAP Demo Server: coap://californium.eclipseprojects.io:5683/ - Try: coap-client -m get coap://californium.eclipseprojects.io:5683/.well-known/core

  1. CoAP.me Public Test Server: coap://coap.me:5683/
    • Test GET, POST, PUT, DELETE without setting up your own server

Code Examples: - CoAP Examples Repository - aiocoap Tutorial - ESP32 CoAP Temperature Sensor

Video Tutorials: - Building IoT with CoAP - IoT Developer Conference - CoAP Deep Dive - Eclipse Foundation - Constrained Devices and CoAP - IETF Educational Series

1226.7 Troubleshooting Common Issues

WarningCommon Problems and Solutions
Symptom Likely Cause Solution
Request times out UDP packet loss or no ACK Increase retransmission timeout, use CON messages instead of NON, check network quality
Confirmable message never acknowledged Server down or wrong endpoint Verify server is running, check CoAP URI format (coap://host:port/path)
Block transfer fails mid-stream MTU too large or packet fragmentation Reduce block size (default 1024 bytes to 512 or 256), check network MTU settings
Observe notifications stop Server crashed or network partition Re-establish observe relationship, implement client-side timeout detection
Multicast discovery finds no devices Wrong multicast address or routing Use FF02::FD for link-local or FF05::FD for site-local, check IPv6 multicast routing
DTLS handshake fails PSK mismatch or certificate error Verify pre-shared keys match exactly, check certificate validity for certificate mode
Response code 4.04 Not Found Wrong resource path Check resource URI case-sensitivity, verify resource exists on server
Response code 4.05 Method Not Allowed Unsupported method on resource Confirm resource supports GET/POST/PUT/DELETE, check resource permissions

Debug Checklist:

  • Connection and Discovery Issues:
  • Request/Response Problems:
  • Observe and Block Transfer Issues:
  • Performance and Reliability:
  • Security (DTLS) Issues:

Common Error Codes:

  • 2.01 Created: Resource successfully created (POST response)
  • 2.02 Deleted: Resource successfully deleted
  • 2.03 Valid: Resource still valid (cache validation)
  • 2.04 Changed: Resource successfully updated (PUT response)
  • 2.05 Content: Resource content returned (GET response)
  • 4.00 Bad Request: Malformed request or invalid options
  • 4.01 Unauthorized: Authentication required or failed
  • 4.04 Not Found: Resource does not exist
  • 4.05 Method Not Allowed: HTTP method not supported on resource
  • 5.00 Internal Server Error: Server encountered error processing request
  • 5.03 Service Unavailable: Server temporarily unable to handle request

Tools for Debugging:

  • libcoap tools: coap-client and coap-server for testing
  • Copper (Cu): Firefox/Chrome plugin for CoAP browsing (deprecated but useful)
  • Wireshark: CoAP dissector for packet analysis (filter: coap)
  • tcpdump: Capture UDP packets (tcpdump -i any port 5683 -vv)
  • Eclipse Californium: Java-based CoAP library with extensive logging
  • aiocoap: Python library with good debugging output

1226.8 Common Pitfalls

WarningCommon Pitfall: CoAP Message Size Exceeds MTU

The mistake: Sending CoAP payloads larger than the network MTU (typically 1280 bytes for IPv6, often much smaller for constrained networks like 6LoWPAN with 127-byte frames), causing silent packet drops or fragmentation failures.

Symptoms: - Large GET responses never arrive at the client - PUT/POST requests with substantial payloads fail intermittently - Works on local Wi-Fi but fails over 6LoWPAN or constrained networks - Wireshark shows fragmented packets but no reassembled response

Why it happens: CoAP runs over UDP, which doesn’t handle fragmentation gracefully: - IPv6 minimum MTU: 1280 bytes, but CoAP payload should be much smaller - 6LoWPAN frame: 127 bytes maximum, ~80 bytes after headers - UDP fragmentation: If any fragment is lost, entire message is lost - No automatic retransmission of individual fragments

The fix:

# Use CoAP Block-wise Transfer (RFC 7959) for large payloads
from aiocoap import Message, Context
from aiocoap.numbers.codes import GET

async def get_large_resource(uri):
    context = await Context.create_client_context()

    # Request with Block2 option - library handles chunking
    request = Message(code=GET, uri=uri)
    # Block size: 64 bytes (szx=2), 128 bytes (szx=3), 256 bytes (szx=4)
    # Smaller blocks = more round trips but works on constrained networks

    response = await context.request(request).response
    return response.payload  # Library reassembles blocks automatically
// Embedded C: Check payload size before sending
#define COAP_MAX_PAYLOAD_6LOWPAN  64   // Safe for 802.15.4
#define COAP_MAX_PAYLOAD_UDP      1024 // Safe for most networks

size_t max_payload = is_constrained_network() ?
    COAP_MAX_PAYLOAD_6LOWPAN : COAP_MAX_PAYLOAD_UDP;

if (payload_len > max_payload) {
    // Use Block1 (request) or Block2 (response) transfer
    return coap_send_blockwise(payload, payload_len, max_payload);
}

Prevention: Design payloads to fit in 64-128 bytes for 6LoWPAN networks. Use Block-wise Transfer for firmware updates, large configurations, or file downloads. Test on the actual constrained network, not just Wi-Fi.

WarningCommon Pitfall: Misusing CON vs NON Message Types

The mistake: Using Confirmable (CON) messages for all communications because “reliability is important,” leading to excessive battery drain and network congestion, or using Non-Confirmable (NON) for critical commands where delivery must be guaranteed.

Symptoms: - Battery-powered sensors lasting weeks instead of years - Unnecessary retransmission storms when network is lossy - Commands occasionally not reaching actuators (lights, locks) - High latency due to waiting for ACKs on every message

Why it happens: Developers often misunderstand the trade-offs: - CON overuse: HTTP background makes developers expect reliability for everything - NON overuse: Trying to maximize battery life without considering message importance - No hybrid strategy: Treating all messages the same regardless of criticality

The fix:

from aiocoap import Message, Context
from aiocoap.numbers.codes import GET, PUT
from aiocoap.numbers.types import CON, NON

# NON for periodic telemetry (loss acceptable, battery critical)
async def send_temperature_reading(temp):
    request = Message(
        code=PUT,
        mtype=NON,  # Fire-and-forget, ~5x better battery life
        uri='coap://server/sensors/temp',
        payload=f'{temp}'.encode()
    )
    await context.request(request).response

# CON for critical commands (must know if it worked)
async def unlock_door():
    request = Message(
        code=PUT,
        mtype=CON,  # Need acknowledgment for security
        uri='coap://door/lock',
        payload=b'unlock'
    )
    try:
        response = await context.request(request).response
        return response.code.is_successful()
    except Exception:
        return False  # Command failed, alert user

# CON for configuration changes (must be applied)
async def update_reporting_interval(seconds):
    request = Message(
        code=PUT,
        mtype=CON,  # Config must be confirmed
        uri='coap://sensor/config/interval',
        payload=str(seconds).encode()
    )
    return await context.request(request).response

Decision matrix: | Message Type | Use NON | Use CON | |————–|———|———| | Periodic sensor readings | Yes | No | | Alert/alarm notifications | No | Yes | | Device commands (on/off) | No | Yes | | Configuration updates | No | Yes | | Status queries | Depends | Depends | | Firmware chunks | No (use Block) | Yes (Block2 ACKs) |

Prevention: Default to NON for periodic telemetry. Use CON only for commands, configurations, and alerts. Implement a message priority system that selects type based on criticality.

1226.9 What’s Next

Now that you understand CoAP security and implementation patterns, the final chapter provides CoAP Practice and Exercises where you’ll find:

  • Visual reference gallery with protocol diagrams
  • Worked examples with real calculations
  • Hands-on practice exercises
  • Further reading and academic resources