Skip to content

Commit 9187968

Browse files
committed
Show how to do DTLS import and export
1 parent 1d0c480 commit 9187968

6 files changed

Lines changed: 1288 additions & 1 deletion

File tree

dtls/README.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1675,7 +1675,7 @@ if (cont == 1 || cleanup == 1) {
16751675
return 0;
16761676
```
16771677

1678-
The code above was taken directly from the DTLS server nonblocking file.
1678+
The code above was taken directly from the DTLS server nonblocking file.
16791679

16801680
Be sure to keep in mind that the `AwaitDatagram` code is essentially one large loop that will attempt to listen for a client (in a nonblocking fashion) at every iteration, and will close the loop upon a signal passed by the user.
16811681

@@ -1688,3 +1688,76 @@ And that's it! The server has been made into a nonblocking server, and the clien
16881688
2. The Open Group, “setsockopt - set the socket options”, Copyright © 1997, The Single UNIX ® Specification, Version 2
16891689
3. https://en.wikipedia.org/wiki/POSIX_Threads
16901690
4. https://www.quora.com/What-exactly-does-it-mean-for-a-web-server-to-be-blocking-versus-non-blocking
1691+
1692+
## Chapter 6: DTLS Session Export and Import
1693+
1694+
### 6.1 Overview
1695+
1696+
The DTLS session export/import feature allows you to serialize a DTLS session's state (including keys, cipher specs, sequence numbers, and peer information) to a buffer, save it to persistent storage, and later restore it to continue communication without performing a new handshake.
1697+
1698+
This is useful for:
1699+
- **Session migration**: Moving a DTLS session between processes
1700+
- **Load balancing**: Distributing sessions across multiple servers
1701+
- **Persistence**: Saving session state across application restarts
1702+
- **Failover**: Restoring sessions after a crash or restart
1703+
1704+
**Important Security Note**: The exported session data contains sensitive cryptographic keys. These examples encrypt the session data with AES-256-CBC before saving to disk. In production, use a secure key management system instead of hard-coded keys.
1705+
1706+
### 6.2 Building wolfSSL with Session Export Support
1707+
1708+
To use these examples, wolfSSL must be compiled with DTLS and session export support:
1709+
1710+
```bash
1711+
cd wolfssl
1712+
./autogen.sh
1713+
./configure --enable-dtls --enable-sessionexport
1714+
make
1715+
sudo make install
1716+
sudo ldconfig
1717+
```
1718+
1719+
### 6.3 Building the Examples
1720+
1721+
```bash
1722+
cd wolfssl-examples/dtls
1723+
make client-dtls-export client-dtls-import server-dtls-export server-dtls-import
1724+
```
1725+
1726+
### 6.4 Running the Examples
1727+
1728+
In a terminal run the server export application.
1729+
1730+
```bash
1731+
./server-dtls-export
1732+
```
1733+
1734+
1735+
In another terminal, run the client export application, enter a message and then press enter.
1736+
```bash
1737+
./client-dtls-export 127.0.0.1
1738+
```
1739+
1740+
Both application will then exit. You can find new .bin files that are generated.
1741+
In the first terminal, run the the server import application.
1742+
1743+
```bash
1744+
./server-dtls-export
1745+
```
1746+
1747+
It will load the server binary file. In the second terminal, run the client import application, type a message and press enter. The server will be able to get the message and decrypt it as if the two applications had never been interrupted.
1748+
.
1749+
1750+
### 6.5 Session Data Encryption
1751+
1752+
The examples use AES-256-CBC to encrypt the session data before saving to disk. The file format is:
1753+
1754+
```
1755+
[4 bytes: original data length]
1756+
[16 bytes: random IV]
1757+
[N bytes: AES-CBC encrypted session]
1758+
```
1759+
1760+
**Warning**: The examples use a hard-coded AES key for demonstration purposes. In production:
1761+
- Derive keys from a secure source
1762+
- Consider using authenticated encryption (AES-GCM)
1763+
- Implement proper key rotation

dtls/client-dtls-export.c

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/* client-dtls-export.c
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL. (formerly known as CyaSSL)
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+
*
21+
*=============================================================================
22+
*
23+
* DTLS client that exports its session after handshake.
24+
* The exported session is encrypted with AES and saved to a file.
25+
* This session can later be imported by client-dtls-import to resume
26+
* communication without a new handshake.
27+
*
28+
* Requires wolfSSL compiled with:
29+
* ./configure --enable-dtls --enable-sessionexport
30+
*/
31+
32+
#include "dtls-export-common.h"
33+
#include <unistd.h>
34+
#include <netdb.h>
35+
#include <signal.h>
36+
#include <sys/socket.h>
37+
#include <arpa/inet.h>
38+
#include <netinet/in.h>
39+
40+
#define MAXLINE 4096
41+
#define SERV_PORT 11111
42+
43+
static void Usage(const char* progName)
44+
{
45+
printf("Usage: %s <server IP> [session_file]\n", progName);
46+
printf(" server IP - IP address of the DTLS server\n");
47+
printf(" session_file - Optional: file to save session (default: %s)\n",
48+
DEFAULT_CLIENT_SESSION_FILE);
49+
}
50+
51+
int main(int argc, char** argv)
52+
{
53+
int sockfd = 0;
54+
int ret;
55+
struct sockaddr_in servAddr;
56+
WOLFSSL* ssl = NULL;
57+
WOLFSSL_CTX* ctx = NULL;
58+
char certs[] = "../certs/ca-cert.pem";
59+
char sendLine[MAXLINE];
60+
char recvLine[MAXLINE - 1];
61+
const char* sessionFile = DEFAULT_CLIENT_SESSION_FILE;
62+
unsigned char* sessionBuf = NULL;
63+
unsigned int sessionSz = 0;
64+
int n;
65+
66+
/* Program argument checking */
67+
if (argc < 2 || argc > 3) {
68+
Usage(argv[0]);
69+
return 1;
70+
}
71+
72+
if (argc == 3) {
73+
sessionFile = argv[2];
74+
}
75+
76+
/* Initialize wolfSSL */
77+
wolfSSL_Init();
78+
79+
/* Create DTLS 1.2 context */
80+
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
81+
if (ctx == NULL) {
82+
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
83+
ret = 1;
84+
goto cleanup;
85+
}
86+
87+
/* Load CA certificates */
88+
ret = wolfSSL_CTX_load_verify_locations(ctx, certs, NULL);
89+
if (ret != SSL_SUCCESS) {
90+
fprintf(stderr, "Error: Failed to load CA cert %s\n", certs);
91+
ret = 1;
92+
goto cleanup;
93+
}
94+
95+
/* Create SSL object */
96+
ssl = wolfSSL_new(ctx);
97+
if (ssl == NULL) {
98+
fprintf(stderr, "Error: wolfSSL_new failed\n");
99+
ret = 1;
100+
goto cleanup;
101+
}
102+
103+
/* Setup server address */
104+
memset(&servAddr, 0, sizeof(servAddr));
105+
servAddr.sin_family = AF_INET;
106+
servAddr.sin_port = htons(SERV_PORT);
107+
if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) {
108+
fprintf(stderr, "Error: Invalid IP address: %s\n", argv[1]);
109+
ret = 1;
110+
goto cleanup;
111+
}
112+
113+
/* Set DTLS peer */
114+
wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr));
115+
116+
/* Create UDP socket */
117+
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
118+
if (sockfd < 0) {
119+
fprintf(stderr, "Error: Cannot create socket\n");
120+
ret = 1;
121+
goto cleanup;
122+
}
123+
124+
/* Set the socket file descriptor */
125+
wolfSSL_set_fd(ssl, sockfd);
126+
127+
/* Perform DTLS handshake */
128+
printf("Connecting to server %s:%d...\n", argv[1], SERV_PORT);
129+
ret = wolfSSL_connect(ssl);
130+
if (ret != SSL_SUCCESS) {
131+
int err = wolfSSL_get_error(ssl, ret);
132+
fprintf(stderr, "Error: wolfSSL_connect failed: %d (%s)\n",
133+
err, wolfSSL_ERR_reason_error_string(err));
134+
ret = 1;
135+
goto cleanup;
136+
}
137+
printf("DTLS handshake successful!\n");
138+
139+
/* Export the session */
140+
printf("Exporting DTLS session...\n");
141+
142+
/* First call to get required buffer size */
143+
ret = wolfSSL_dtls_export(ssl, NULL, &sessionSz);
144+
if (ret != 0 && sessionSz == 0) {
145+
fprintf(stderr, "Error: wolfSSL_dtls_export (get size) failed: %d\n",
146+
ret);
147+
ret = 1;
148+
goto cleanup;
149+
}
150+
151+
/* Allocate buffer for session data */
152+
sessionBuf = (unsigned char*)malloc(sessionSz);
153+
if (sessionBuf == NULL) {
154+
fprintf(stderr, "Error: Memory allocation failed\n");
155+
ret = 1;
156+
goto cleanup;
157+
}
158+
159+
/* Export the session */
160+
ret = wolfSSL_dtls_export(ssl, sessionBuf, &sessionSz);
161+
if (ret <= 0) {
162+
fprintf(stderr, "Error: wolfSSL_dtls_export failed: %d\n", ret);
163+
ret = 1;
164+
goto cleanup;
165+
}
166+
printf("Session exported: %d bytes\n", ret);
167+
sessionSz = ret;
168+
169+
/* Save encrypted session to file */
170+
ret = SaveEncryptedSession(sessionFile, sessionBuf, sessionSz);
171+
if (ret != 0) {
172+
fprintf(stderr, "Error: Failed to save encrypted session\n");
173+
ret = 1;
174+
goto cleanup;
175+
}
176+
177+
/* Send a test message */
178+
printf("\nEnter message to send (or press Enter to skip): ");
179+
if (fgets(sendLine, MAXLINE, stdin) != NULL && sendLine[0] != '\n') {
180+
ret = wolfSSL_write(ssl, sendLine, (int)strlen(sendLine));
181+
if (ret != (int)strlen(sendLine)) {
182+
fprintf(stderr, "Error: wolfSSL_write failed\n");
183+
}
184+
else {
185+
printf("Sent: %s", sendLine);
186+
187+
/* Read response */
188+
n = wolfSSL_read(ssl, recvLine, sizeof(recvLine) - 1);
189+
if (n > 0) {
190+
recvLine[n] = '\0';
191+
printf("Received: %s", recvLine);
192+
}
193+
}
194+
}
195+
196+
printf("\nSession exported and saved to: %s\n", sessionFile);
197+
printf("You can now use client-dtls-import to resume this session.\n");
198+
ret = 0;
199+
200+
cleanup:
201+
if (sessionBuf != NULL) free(sessionBuf);
202+
if (ssl != NULL) {
203+
wolfSSL_shutdown(ssl);
204+
wolfSSL_free(ssl);
205+
}
206+
if (sockfd > 0) close(sockfd);
207+
if (ctx != NULL) wolfSSL_CTX_free(ctx);
208+
wolfSSL_Cleanup();
209+
210+
return ret;
211+
}

0 commit comments

Comments
 (0)