1226CoAP 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
Show code
{const container =document.getElementById('kc-coap-8');if (container &&typeof InlineKnowledgeCheck !=='undefined') { container.innerHTML=''; container.appendChild(InlineKnowledgeCheck.create({question:"A healthcare company is deploying wearable patient monitors that use CoAP to send vital signs to hospital servers. The HIPAA compliance officer requires end-to-end encryption. The development team proposes using regular CoAP (port 5683) with application-layer encryption of the JSON payload. What security concern does this approach NOT address?",options: [ {text:"The payload is encrypted, so all data is protected - this approach is HIPAA compliant",correct:false,feedback:"Incorrect. While payload encryption protects the vital signs data, CoAP metadata (URIs, options) remains visible. An attacker could see which patients' devices are communicating, when, and which resources they're accessing (e.g., /patient/123/heartrate). This metadata can reveal sensitive health patterns."}, {text:"CoAP headers, URIs, and options remain unencrypted, exposing metadata like patient IDs and resource paths to network observers",correct:true,feedback:"Correct! Application-layer encryption only protects the payload. CoAP headers, URI paths (/patient/12345/vitals), options (content-type, observe), and message types remain visible to anyone sniffing the network. DTLS (CoAPs on port 5684) encrypts the entire CoAP message including all metadata, providing true end-to-end protection required for healthcare compliance."}, {text:"The encryption adds too much overhead for constrained devices to handle",correct:false,feedback:"Incorrect. While encryption does add overhead, this is a trade-off healthcare applications must accept. Modern constrained devices can handle DTLS with hardware acceleration. The question is about security gaps, not performance."}, {text:"Pre-shared keys should be used instead of certificates for better security",correct:false,feedback:"Incorrect. Both PSK and certificates are valid DTLS authentication methods. Certificates actually provide better security (no shared secret to compromise) but require more resources. The main issue here is using no transport security at all, not the authentication method."} ],difficulty:"hard",topic:"coap-dtls-security" })); }}
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:
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# secondsfor attempt inrange(MAX_RETRIES): send_message(msg)if wait_for_ack(RETRY_INTERVAL):break# GOOD: Exponential backoff per RFC 7252ACK_TIMEOUT =2.0# Initial timeout (2 seconds)ACK_RANDOM_FACTOR =1.5# Randomization factorMAX_RETRANSMIT =4# Maximum retriesdef coap_transmit(msg): timeout = ACK_TIMEOUT * (1+ random.random() * (ACK_RANDOM_FACTOR -1))for attempt inrange(MAX_RETRANSMIT +1): send_message(msg)if wait_for_ack(timeout):returnTrue timeout *=2# Double timeout each retry: 2s, 4s, 8s, 16sreturnFalse# 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
coap-client (libcoap): Command-line CoAP client for testing
# GET requestcoap-client-m get coap://localhost/temperature# POST with payloadcoap-client-m post coap://localhost/sensor -e"22.5"# Observe resourcecoap-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
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
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 payloadsfrom aiocoap import Message, Contextfrom aiocoap.numbers.codes import GETasyncdef 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).responsereturn 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 networkssize_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) transferreturn 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, Contextfrom aiocoap.numbers.codes import GET, PUTfrom aiocoap.numbers.types import CON, NON# NON for periodic telemetry (loss acceptable, battery critical)asyncdef 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)asyncdef 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).responsereturn response.code.is_successful()exceptException:returnFalse# Command failed, alert user# CON for configuration changes (must be applied)asyncdef update_reporting_interval(seconds): request = Message( code=PUT, mtype=CON, # Config must be confirmed uri='coap://sensor/config/interval', payload=str(seconds).encode() )returnawait 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: