Show how to do DTLS import and export
parent
1d0c480da4
commit
9187968347
|
|
@ -1675,7 +1675,7 @@ if (cont == 1 || cleanup == 1) {
|
|||
return 0;
|
||||
```
|
||||
|
||||
The code above was taken directly from the DTLS server nonblocking file.
|
||||
The code above was taken directly from the DTLS server nonblocking file.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -1688,3 +1688,76 @@ And that's it! The server has been made into a nonblocking server, and the clien
|
|||
2. The Open Group, “setsockopt - set the socket options”, Copyright © 1997, The Single UNIX ® Specification, Version 2
|
||||
3. https://en.wikipedia.org/wiki/POSIX_Threads
|
||||
4. https://www.quora.com/What-exactly-does-it-mean-for-a-web-server-to-be-blocking-versus-non-blocking
|
||||
|
||||
## Chapter 6: DTLS Session Export and Import
|
||||
|
||||
### 6.1 Overview
|
||||
|
||||
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.
|
||||
|
||||
This is useful for:
|
||||
- **Session migration**: Moving a DTLS session between processes
|
||||
- **Load balancing**: Distributing sessions across multiple servers
|
||||
- **Persistence**: Saving session state across application restarts
|
||||
- **Failover**: Restoring sessions after a crash or restart
|
||||
|
||||
**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.
|
||||
|
||||
### 6.2 Building wolfSSL with Session Export Support
|
||||
|
||||
To use these examples, wolfSSL must be compiled with DTLS and session export support:
|
||||
|
||||
```bash
|
||||
cd wolfssl
|
||||
./autogen.sh
|
||||
./configure --enable-dtls --enable-sessionexport
|
||||
make
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
|
||||
### 6.3 Building the Examples
|
||||
|
||||
```bash
|
||||
cd wolfssl-examples/dtls
|
||||
make client-dtls-export client-dtls-import server-dtls-export server-dtls-import
|
||||
```
|
||||
|
||||
### 6.4 Running the Examples
|
||||
|
||||
In a terminal run the server export application.
|
||||
|
||||
```bash
|
||||
./server-dtls-export
|
||||
```
|
||||
|
||||
|
||||
In another terminal, run the client export application, enter a message and then press enter.
|
||||
```bash
|
||||
./client-dtls-export 127.0.0.1
|
||||
```
|
||||
|
||||
Both application will then exit. You can find new .bin files that are generated.
|
||||
In the first terminal, run the the server import application.
|
||||
|
||||
```bash
|
||||
./server-dtls-export
|
||||
```
|
||||
|
||||
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.
|
||||
.
|
||||
|
||||
### 6.5 Session Data Encryption
|
||||
|
||||
The examples use AES-256-CBC to encrypt the session data before saving to disk. The file format is:
|
||||
|
||||
```
|
||||
[4 bytes: original data length]
|
||||
[16 bytes: random IV]
|
||||
[N bytes: AES-CBC encrypted session]
|
||||
```
|
||||
|
||||
**Warning**: The examples use a hard-coded AES key for demonstration purposes. In production:
|
||||
- Derive keys from a secure source
|
||||
- Consider using authenticated encryption (AES-GCM)
|
||||
- Implement proper key rotation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,211 @@
|
|||
/* client-dtls-export.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* DTLS client that exports its session after handshake.
|
||||
* The exported session is encrypted with AES and saved to a file.
|
||||
* This session can later be imported by client-dtls-import to resume
|
||||
* communication without a new handshake.
|
||||
*
|
||||
* Requires wolfSSL compiled with:
|
||||
* ./configure --enable-dtls --enable-sessionexport
|
||||
*/
|
||||
|
||||
#include "dtls-export-common.h"
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define MAXLINE 4096
|
||||
#define SERV_PORT 11111
|
||||
|
||||
static void Usage(const char* progName)
|
||||
{
|
||||
printf("Usage: %s <server IP> [session_file]\n", progName);
|
||||
printf(" server IP - IP address of the DTLS server\n");
|
||||
printf(" session_file - Optional: file to save session (default: %s)\n",
|
||||
DEFAULT_CLIENT_SESSION_FILE);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int sockfd = 0;
|
||||
int ret;
|
||||
struct sockaddr_in servAddr;
|
||||
WOLFSSL* ssl = NULL;
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
char certs[] = "../certs/ca-cert.pem";
|
||||
char sendLine[MAXLINE];
|
||||
char recvLine[MAXLINE - 1];
|
||||
const char* sessionFile = DEFAULT_CLIENT_SESSION_FILE;
|
||||
unsigned char* sessionBuf = NULL;
|
||||
unsigned int sessionSz = 0;
|
||||
int n;
|
||||
|
||||
/* Program argument checking */
|
||||
if (argc < 2 || argc > 3) {
|
||||
Usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
sessionFile = argv[2];
|
||||
}
|
||||
|
||||
/* Initialize wolfSSL */
|
||||
wolfSSL_Init();
|
||||
|
||||
/* Create DTLS 1.2 context */
|
||||
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load CA certificates */
|
||||
ret = wolfSSL_CTX_load_verify_locations(ctx, certs, NULL);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: Failed to load CA cert %s\n", certs);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create SSL object */
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Setup server address */
|
||||
memset(&servAddr, 0, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_port = htons(SERV_PORT);
|
||||
if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) {
|
||||
fprintf(stderr, "Error: Invalid IP address: %s\n", argv[1]);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set DTLS peer */
|
||||
wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr));
|
||||
|
||||
/* Create UDP socket */
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
fprintf(stderr, "Error: Cannot create socket\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set the socket file descriptor */
|
||||
wolfSSL_set_fd(ssl, sockfd);
|
||||
|
||||
/* Perform DTLS handshake */
|
||||
printf("Connecting to server %s:%d...\n", argv[1], SERV_PORT);
|
||||
ret = wolfSSL_connect(ssl);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
int err = wolfSSL_get_error(ssl, ret);
|
||||
fprintf(stderr, "Error: wolfSSL_connect failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("DTLS handshake successful!\n");
|
||||
|
||||
/* Export the session */
|
||||
printf("Exporting DTLS session...\n");
|
||||
|
||||
/* First call to get required buffer size */
|
||||
ret = wolfSSL_dtls_export(ssl, NULL, &sessionSz);
|
||||
if (ret != 0 && sessionSz == 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_export (get size) failed: %d\n",
|
||||
ret);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate buffer for session data */
|
||||
sessionBuf = (unsigned char*)malloc(sessionSz);
|
||||
if (sessionBuf == NULL) {
|
||||
fprintf(stderr, "Error: Memory allocation failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Export the session */
|
||||
ret = wolfSSL_dtls_export(ssl, sessionBuf, &sessionSz);
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_export failed: %d\n", ret);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("Session exported: %d bytes\n", ret);
|
||||
sessionSz = ret;
|
||||
|
||||
/* Save encrypted session to file */
|
||||
ret = SaveEncryptedSession(sessionFile, sessionBuf, sessionSz);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error: Failed to save encrypted session\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Send a test message */
|
||||
printf("\nEnter message to send (or press Enter to skip): ");
|
||||
if (fgets(sendLine, MAXLINE, stdin) != NULL && sendLine[0] != '\n') {
|
||||
ret = wolfSSL_write(ssl, sendLine, (int)strlen(sendLine));
|
||||
if (ret != (int)strlen(sendLine)) {
|
||||
fprintf(stderr, "Error: wolfSSL_write failed\n");
|
||||
}
|
||||
else {
|
||||
printf("Sent: %s", sendLine);
|
||||
|
||||
/* Read response */
|
||||
n = wolfSSL_read(ssl, recvLine, sizeof(recvLine) - 1);
|
||||
if (n > 0) {
|
||||
recvLine[n] = '\0';
|
||||
printf("Received: %s", recvLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nSession exported and saved to: %s\n", sessionFile);
|
||||
printf("You can now use client-dtls-import to resume this session.\n");
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (sessionBuf != NULL) free(sessionBuf);
|
||||
if (ssl != NULL) {
|
||||
wolfSSL_shutdown(ssl);
|
||||
wolfSSL_free(ssl);
|
||||
}
|
||||
if (sockfd > 0) close(sockfd);
|
||||
if (ctx != NULL) wolfSSL_CTX_free(ctx);
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/* client-dtls-import.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* DTLS client that imports a previously exported session.
|
||||
* The session is loaded from an encrypted file and decrypted with AES.
|
||||
* This allows resuming communication without a new handshake.
|
||||
*
|
||||
* Requires wolfSSL compiled with:
|
||||
* ./configure --enable-dtls --enable-sessionexport
|
||||
*/
|
||||
|
||||
#include "dtls-export-common.h"
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define MAXLINE 4096
|
||||
#define SERV_PORT 11111
|
||||
|
||||
static void Usage(const char* progName)
|
||||
{
|
||||
printf("Usage: %s <server IP> [session_file]\n", progName);
|
||||
printf(" server IP - IP address of the DTLS server\n");
|
||||
printf(" session_file - Optional: file to load session from (default: %s)\n",
|
||||
DEFAULT_CLIENT_SESSION_FILE);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int sockfd = 0;
|
||||
int ret;
|
||||
struct sockaddr_in servAddr;
|
||||
WOLFSSL* ssl = NULL;
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
char sendLine[MAXLINE];
|
||||
char recvLine[MAXLINE - 1];
|
||||
const char* sessionFile = DEFAULT_CLIENT_SESSION_FILE;
|
||||
unsigned char* sessionBuf = NULL;
|
||||
unsigned int sessionSz = 0;
|
||||
int n;
|
||||
|
||||
/* Program argument checking */
|
||||
if (argc < 2 || argc > 3) {
|
||||
Usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
sessionFile = argv[2];
|
||||
}
|
||||
|
||||
/* Initialize wolfSSL */
|
||||
wolfSSL_Init();
|
||||
|
||||
/* Create DTLS 1.2 context */
|
||||
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create SSL object */
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load encrypted session from file */
|
||||
printf("Loading session from %s...\n", sessionFile);
|
||||
sessionBuf = LoadEncryptedSession(sessionFile, &sessionSz);
|
||||
if (sessionBuf == NULL) {
|
||||
fprintf(stderr, "Error: Failed to load session from file\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Import the session */
|
||||
printf("Importing DTLS session (%u bytes)...\n", sessionSz);
|
||||
ret = wolfSSL_dtls_import(ssl, sessionBuf, sessionSz);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_import failed: %d\n", ret);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("Session imported successfully!\n");
|
||||
|
||||
/* Setup server address */
|
||||
memset(&servAddr, 0, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_port = htons(SERV_PORT);
|
||||
if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) {
|
||||
fprintf(stderr, "Error: Invalid IP address: %s\n", argv[1]);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set DTLS peer */
|
||||
wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr));
|
||||
|
||||
/* Create UDP socket */
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
fprintf(stderr, "Error: Cannot create socket\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set the socket file descriptor */
|
||||
wolfSSL_set_fd(ssl, sockfd);
|
||||
|
||||
printf("Session restored - no handshake needed!\n");
|
||||
printf("Ready to communicate with server %s:%d\n\n", argv[1], SERV_PORT);
|
||||
|
||||
/* Send messages using the imported session */
|
||||
printf("Enter message to send (or 'quit' to exit):\n");
|
||||
while (fgets(sendLine, MAXLINE, stdin) != NULL) {
|
||||
if (strncmp(sendLine, "quit", 4) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send message */
|
||||
ret = wolfSSL_write(ssl, sendLine, (int)strlen(sendLine));
|
||||
if (ret != (int)strlen(sendLine)) {
|
||||
int err = wolfSSL_get_error(ssl, ret);
|
||||
fprintf(stderr, "Error: wolfSSL_write failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
break;
|
||||
}
|
||||
printf("Sent: %s", sendLine);
|
||||
|
||||
/* Read response */
|
||||
n = wolfSSL_read(ssl, recvLine, sizeof(recvLine) - 1);
|
||||
if (n > 0) {
|
||||
recvLine[n] = '\0';
|
||||
printf("Received: %s", recvLine);
|
||||
}
|
||||
else {
|
||||
int err = wolfSSL_get_error(ssl, n);
|
||||
if (err != SSL_ERROR_WANT_READ) {
|
||||
fprintf(stderr, "Error: wolfSSL_read failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nEnter message (or 'quit' to exit):\n");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (sessionBuf != NULL) free(sessionBuf);
|
||||
if (ssl != NULL) {
|
||||
wolfSSL_shutdown(ssl);
|
||||
wolfSSL_free(ssl);
|
||||
}
|
||||
if (sockfd > 0) close(sockfd);
|
||||
if (ctx != NULL) wolfSSL_CTX_free(ctx);
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
/* dtls-export-common.h
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* Common header for DTLS session export/import examples.
|
||||
* Provides AES encryption/decryption for session data protection.
|
||||
*/
|
||||
|
||||
#ifndef DTLS_EXPORT_COMMON_H
|
||||
#define DTLS_EXPORT_COMMON_H
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Default file for session export/import */
|
||||
#define DEFAULT_CLIENT_SESSION_FILE "dtls_client_session.bin"
|
||||
#define DEFAULT_SERVER_SESSION_FILE "dtls_server_session.bin"
|
||||
|
||||
/* AES-256-CBC key (32 bytes) - In production, use a securely generated key.*/
|
||||
static const unsigned char AES_KEY[32] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
|
||||
};
|
||||
|
||||
/* AES block size */
|
||||
#define AES_BLOCK_SZ 16
|
||||
|
||||
/* File format:
|
||||
* [4 bytes: original data length]
|
||||
* [16 bytes: IV]
|
||||
* [N bytes: encrypted data (padded to AES_BLOCK_SZ)]
|
||||
*/
|
||||
|
||||
/*
|
||||
* Encrypt session data and save to file
|
||||
* Returns 0 on success, negative on error
|
||||
*/
|
||||
int SaveEncryptedSession(const char* filename,
|
||||
const unsigned char* sessionData,
|
||||
unsigned int sessionSz)
|
||||
{
|
||||
FILE* fp = NULL;
|
||||
Aes aes;
|
||||
WC_RNG rng;
|
||||
unsigned char iv[AES_BLOCK_SZ];
|
||||
unsigned char* paddedData = NULL;
|
||||
unsigned char* encryptedData = NULL;
|
||||
unsigned int paddedSz;
|
||||
unsigned int padding;
|
||||
int ret = 0;
|
||||
int aesInit = 0;
|
||||
int rngInit = 0;
|
||||
|
||||
/* Calculate padded size (must be multiple of AES_BLOCK_SZ) */
|
||||
padding = AES_BLOCK_SZ - (sessionSz % AES_BLOCK_SZ);
|
||||
paddedSz = sessionSz + padding;
|
||||
|
||||
/* Initialize RNG for IV generation */
|
||||
ret = wc_InitRng(&rng);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_InitRng failed: %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
rngInit = 1;
|
||||
|
||||
/* Generate random IV */
|
||||
ret = wc_RNG_GenerateBlock(&rng, iv, AES_BLOCK_SZ);
|
||||
if (ret != 0) {
|
||||
printf("Error: Failed to generate IV: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate buffers */
|
||||
paddedData = (unsigned char*)malloc(paddedSz);
|
||||
encryptedData = (unsigned char*)malloc(paddedSz);
|
||||
if (paddedData == NULL || encryptedData == NULL) {
|
||||
printf("Error: Memory allocation failed\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Copy data and add PKCS#7 padding */
|
||||
memcpy(paddedData, sessionData, sessionSz);
|
||||
memset(paddedData + sessionSz, (int)padding, padding);
|
||||
|
||||
/* Initialize AES */
|
||||
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesInit failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
aesInit = 1;
|
||||
|
||||
/* Set AES key for encryption */
|
||||
ret = wc_AesSetKey(&aes, AES_KEY, sizeof(AES_KEY), iv, AES_ENCRYPTION);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesSetKey failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Encrypt the data */
|
||||
ret = wc_AesCbcEncrypt(&aes, encryptedData, paddedData, paddedSz);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesCbcEncrypt failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Write to file */
|
||||
fp = fopen(filename, "wb");
|
||||
if (fp == NULL) {
|
||||
printf("Error: Cannot open file %s for writing\n", filename);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Write original size (4 bytes, big-endian) */
|
||||
{
|
||||
unsigned char sizeBuf[4];
|
||||
sizeBuf[0] = (sessionSz >> 24) & 0xFF;
|
||||
sizeBuf[1] = (sessionSz >> 16) & 0xFF;
|
||||
sizeBuf[2] = (sessionSz >> 8) & 0xFF;
|
||||
sizeBuf[3] = sessionSz & 0xFF;
|
||||
if (fwrite(sizeBuf, 1, 4, fp) != 4) {
|
||||
printf("Error: Failed to write size to file\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write IV */
|
||||
if (fwrite(iv, 1, AES_BLOCK_SZ, fp) != AES_BLOCK_SZ) {
|
||||
printf("Error: Failed to write IV to file\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Write encrypted data */
|
||||
if (fwrite(encryptedData, 1, paddedSz, fp) != paddedSz) {
|
||||
printf("Error: Failed to write encrypted data to file\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Session saved to %s (%u bytes encrypted)\n", filename, paddedSz);
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (fp != NULL) fclose(fp);
|
||||
if (paddedData != NULL) free(paddedData);
|
||||
if (encryptedData != NULL) free(encryptedData);
|
||||
if (aesInit) wc_AesFree(&aes);
|
||||
if (rngInit) wc_FreeRng(&rng);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load and decrypt session data from file
|
||||
* Returns allocated session data (caller must free), or NULL on error
|
||||
* sessionSz is set to the size of the returned data
|
||||
*/
|
||||
unsigned char* LoadEncryptedSession(const char* filename,
|
||||
unsigned int* sessionSz)
|
||||
{
|
||||
FILE* fp = NULL;
|
||||
Aes aes;
|
||||
unsigned char iv[AES_BLOCK_SZ];
|
||||
unsigned char sizeBuf[4];
|
||||
unsigned char* encryptedData = NULL;
|
||||
unsigned char* decryptedData = NULL;
|
||||
unsigned int originalSz;
|
||||
unsigned int encryptedSz;
|
||||
long fileSize;
|
||||
int ret = 0;
|
||||
int aesInit = 0;
|
||||
|
||||
/* Open file */
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == NULL) {
|
||||
printf("Error: Cannot open file %s for reading\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get file size */
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fileSize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (fileSize < (4 + AES_BLOCK_SZ + AES_BLOCK_SZ)) {
|
||||
printf("Error: File too small to contain valid session data\n");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read original size */
|
||||
if (fread(sizeBuf, 1, 4, fp) != 4) {
|
||||
printf("Error: Failed to read size from file\n");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
originalSz = ((unsigned int)sizeBuf[0] << 24) |
|
||||
((unsigned int)sizeBuf[1] << 16) |
|
||||
((unsigned int)sizeBuf[2] << 8) |
|
||||
(unsigned int)sizeBuf[3];
|
||||
|
||||
/* Read IV */
|
||||
if (fread(iv, 1, AES_BLOCK_SZ, fp) != AES_BLOCK_SZ) {
|
||||
printf("Error: Failed to read IV from file\n");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate encrypted data size */
|
||||
encryptedSz = (unsigned int)(fileSize - 4 - AES_BLOCK_SZ);
|
||||
|
||||
/* Allocate buffers */
|
||||
encryptedData = (unsigned char*)malloc(encryptedSz);
|
||||
decryptedData = (unsigned char*)malloc(encryptedSz);
|
||||
if (encryptedData == NULL || decryptedData == NULL) {
|
||||
printf("Error: Memory allocation failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read encrypted data */
|
||||
if (fread(encryptedData, 1, encryptedSz, fp) != encryptedSz) {
|
||||
printf("Error: Failed to read encrypted data from file\n");
|
||||
goto cleanup;
|
||||
}
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
|
||||
/* Initialize AES */
|
||||
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesInit failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
aesInit = 1;
|
||||
|
||||
/* Set AES key for decryption */
|
||||
ret = wc_AesSetKey(&aes, AES_KEY, sizeof(AES_KEY), iv, AES_DECRYPTION);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesSetKey failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Decrypt the data */
|
||||
ret = wc_AesCbcDecrypt(&aes, decryptedData, encryptedData, encryptedSz);
|
||||
if (ret != 0) {
|
||||
printf("Error: wc_AesCbcDecrypt failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Verify padding and original size */
|
||||
if (originalSz > encryptedSz) {
|
||||
printf("Error: Invalid original size in file\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*sessionSz = originalSz;
|
||||
printf("Session loaded from %s (%u bytes)\n", filename, originalSz);
|
||||
|
||||
/* Clean up and return decrypted data */
|
||||
if (encryptedData != NULL) free(encryptedData);
|
||||
if (aesInit) wc_AesFree(&aes);
|
||||
|
||||
return decryptedData;
|
||||
|
||||
cleanup:
|
||||
if (fp != NULL) fclose(fp);
|
||||
if (encryptedData != NULL) free(encryptedData);
|
||||
if (decryptedData != NULL) free(decryptedData);
|
||||
if (aesInit) wc_AesFree(&aes);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* DTLS_EXPORT_COMMON_H */
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
/* server-dtls-export.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* DTLS server that exports its session after handshake.
|
||||
* The exported session is encrypted with AES and saved to a file.
|
||||
* This session can later be imported by server-dtls-import to resume
|
||||
* communication without a new handshake.
|
||||
*
|
||||
* Requires wolfSSL compiled with:
|
||||
* ./configure --enable-dtls --enable-sessionexport
|
||||
*/
|
||||
|
||||
#include "dtls-export-common.h"
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SERV_PORT 11111
|
||||
#define MSGLEN 4096
|
||||
|
||||
static int cleanup = 0;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
cleanup = 1;
|
||||
}
|
||||
|
||||
static void Usage(const char* progName)
|
||||
{
|
||||
printf("Usage: %s [session_file]\n", progName);
|
||||
printf(" session_file - Optional: file to save session (default: %s)\n",
|
||||
DEFAULT_SERVER_SESSION_FILE);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char caCertLoc[] = "../certs/ca-cert.pem";
|
||||
char servCertLoc[] = "../certs/server-cert.pem";
|
||||
char servKeyLoc[] = "../certs/server-key.pem";
|
||||
int ret = 0;
|
||||
int on = 1;
|
||||
int listenfd = 0;
|
||||
int recvLen;
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
struct sockaddr_in servAddr;
|
||||
struct sockaddr_in cliAddr;
|
||||
socklen_t cliLen;
|
||||
socklen_t len = sizeof(int);
|
||||
unsigned char buf[MSGLEN];
|
||||
char ack[] = "Message received!\n";
|
||||
const char* sessionFile = DEFAULT_SERVER_SESSION_FILE;
|
||||
unsigned char* sessionBuf = NULL;
|
||||
unsigned int sessionSz = 0;
|
||||
|
||||
/* Program argument checking */
|
||||
if (argc > 2) {
|
||||
Usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
sessionFile = argv[1];
|
||||
}
|
||||
|
||||
/* Set up signal handler for clean shutdown */
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
/* Initialize wolfSSL */
|
||||
wolfSSL_Init();
|
||||
|
||||
/* Create DTLS 1.2 context */
|
||||
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method());
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load CA certificates */
|
||||
ret = wolfSSL_CTX_load_verify_locations(ctx, caCertLoc, NULL);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: Failed to load CA cert %s\n", caCertLoc);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load server certificate */
|
||||
ret = wolfSSL_CTX_use_certificate_file(ctx, servCertLoc, SSL_FILETYPE_PEM);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: Failed to load server cert %s\n", servCertLoc);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load server private key */
|
||||
ret = wolfSSL_CTX_use_PrivateKey_file(ctx, servKeyLoc, SSL_FILETYPE_PEM);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: Failed to load server key %s\n", servKeyLoc);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create UDP socket */
|
||||
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (listenfd < 0) {
|
||||
fprintf(stderr, "Error: Cannot create socket\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set socket options */
|
||||
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: setsockopt SO_REUSEADDR failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Setup server address */
|
||||
memset(&servAddr, 0, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servAddr.sin_port = htons(SERV_PORT);
|
||||
|
||||
/* Bind socket */
|
||||
ret = bind(listenfd, (struct sockaddr*)&servAddr, sizeof(servAddr));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: bind failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("DTLS server listening on port %d\n", SERV_PORT);
|
||||
printf("Waiting for client connection...\n");
|
||||
|
||||
/* Wait for client connection */
|
||||
cliLen = sizeof(cliAddr);
|
||||
recvLen = (int)recvfrom(listenfd, buf, sizeof(buf), MSG_PEEK,
|
||||
(struct sockaddr*)&cliAddr, &cliLen);
|
||||
if (recvLen < 0) {
|
||||
fprintf(stderr, "Error: recvfrom failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Connect UDP socket to client */
|
||||
ret = connect(listenfd, (struct sockaddr*)&cliAddr, cliLen);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error: UDP connect failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Client connected from %s:%d\n",
|
||||
inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
|
||||
|
||||
/* Create SSL object */
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set DTLS peer */
|
||||
wolfSSL_dtls_set_peer(ssl, &cliAddr, cliLen);
|
||||
|
||||
/* Set socket file descriptor */
|
||||
wolfSSL_set_fd(ssl, listenfd);
|
||||
|
||||
/* Perform DTLS handshake */
|
||||
printf("Performing DTLS handshake...\n");
|
||||
ret = wolfSSL_accept(ssl);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
int err = wolfSSL_get_error(ssl, ret);
|
||||
fprintf(stderr, "Error: wolfSSL_accept failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("DTLS handshake successful!\n");
|
||||
|
||||
/* Export the session */
|
||||
printf("Exporting DTLS session...\n");
|
||||
|
||||
/* First call to get required buffer size */
|
||||
ret = wolfSSL_dtls_export(ssl, NULL, &sessionSz);
|
||||
if (ret != 0 && sessionSz == 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_export (get size) failed: %d\n",
|
||||
ret);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate buffer for session data */
|
||||
sessionBuf = (unsigned char*)malloc(sessionSz);
|
||||
if (sessionBuf == NULL) {
|
||||
fprintf(stderr, "Error: Memory allocation failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Export the session */
|
||||
ret = wolfSSL_dtls_export(ssl, sessionBuf, &sessionSz);
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_export failed: %d\n", ret);
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("Session exported: %d bytes\n", ret);
|
||||
sessionSz = ret;
|
||||
|
||||
/* Save encrypted session to file */
|
||||
ret = SaveEncryptedSession(sessionFile, sessionBuf, sessionSz);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error: Failed to save encrypted session\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Handle one message exchange */
|
||||
printf("\nWaiting for message from client...\n");
|
||||
recvLen = wolfSSL_read(ssl, buf, sizeof(buf) - 1);
|
||||
if (recvLen > 0) {
|
||||
buf[recvLen] = '\0';
|
||||
printf("Received: %s", (char*)buf);
|
||||
|
||||
/* Send acknowledgment */
|
||||
ret = wolfSSL_write(ssl, ack, (int)strlen(ack));
|
||||
if (ret > 0) {
|
||||
printf("Sent: %s", ack);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int err = wolfSSL_get_error(ssl, recvLen);
|
||||
if (err != SSL_ERROR_WANT_READ) {
|
||||
fprintf(stderr, "Warning: wolfSSL_read returned: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nSession exported and saved to: %s\n", sessionFile);
|
||||
printf("You can now use server-dtls-import to resume this session.\n");
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (sessionBuf != NULL) free(sessionBuf);
|
||||
if (ssl != NULL) {
|
||||
wolfSSL_shutdown(ssl);
|
||||
wolfSSL_free(ssl);
|
||||
}
|
||||
if (listenfd > 0) close(listenfd);
|
||||
if (ctx != NULL) wolfSSL_CTX_free(ctx);
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
/* server-dtls-import.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* DTLS server that imports a previously exported session.
|
||||
* The session is loaded from an encrypted file and decrypted with AES.
|
||||
* This allows resuming communication without a new handshake.
|
||||
*
|
||||
* Requires wolfSSL compiled with:
|
||||
* ./configure --enable-dtls --enable-sessionexport
|
||||
*/
|
||||
|
||||
#include "dtls-export-common.h"
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SERV_PORT 11111
|
||||
#define MSGLEN 4096
|
||||
|
||||
static int cleanup = 0;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
cleanup = 1;
|
||||
}
|
||||
|
||||
static void Usage(const char* progName)
|
||||
{
|
||||
printf("Usage: %s [session_file]\n", progName);
|
||||
printf(" session_file - Optional: file to load session from (default: %s)\n",
|
||||
DEFAULT_SERVER_SESSION_FILE);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = 0;
|
||||
int on = 1;
|
||||
int listenfd = 0;
|
||||
int recvLen;
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
struct sockaddr_in servAddr;
|
||||
struct sockaddr_in cliAddr;
|
||||
socklen_t cliLen;
|
||||
socklen_t len = sizeof(int);
|
||||
unsigned char buf[MSGLEN];
|
||||
char ack[] = "Message received (resumed session)!\n";
|
||||
const char* sessionFile = DEFAULT_SERVER_SESSION_FILE;
|
||||
unsigned char* sessionBuf = NULL;
|
||||
unsigned int sessionSz = 0;
|
||||
|
||||
/* Program argument checking */
|
||||
if (argc > 2) {
|
||||
Usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
sessionFile = argv[1];
|
||||
}
|
||||
|
||||
/* Set up signal handler for clean shutdown */
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
/* Initialize wolfSSL */
|
||||
wolfSSL_Init();
|
||||
|
||||
/* Create DTLS 1.2 context */
|
||||
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method());
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create SSL object */
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load encrypted session from file */
|
||||
printf("Loading session from %s...\n", sessionFile);
|
||||
sessionBuf = LoadEncryptedSession(sessionFile, &sessionSz);
|
||||
if (sessionBuf == NULL) {
|
||||
fprintf(stderr, "Error: Failed to load session from file\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Import the session */
|
||||
printf("Importing DTLS session (%u bytes)...\n", sessionSz);
|
||||
ret = wolfSSL_dtls_import(ssl, sessionBuf, sessionSz);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: wolfSSL_dtls_import failed: %d\n", ret);
|
||||
fprintf(stderr, "Make sure wolfSSL was compiled with --enable-sessionexport\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("Session imported successfully!\n");
|
||||
|
||||
/* Create UDP socket */
|
||||
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (listenfd < 0) {
|
||||
fprintf(stderr, "Error: Cannot create socket\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set socket options */
|
||||
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: setsockopt SO_REUSEADDR failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Setup server address */
|
||||
memset(&servAddr, 0, sizeof(servAddr));
|
||||
servAddr.sin_family = AF_INET;
|
||||
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servAddr.sin_port = htons(SERV_PORT);
|
||||
|
||||
/* Bind socket */
|
||||
ret = bind(listenfd, (struct sockaddr*)&servAddr, sizeof(servAddr));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: bind failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Session restored - no handshake needed!\n");
|
||||
printf("DTLS server listening on port %d\n", SERV_PORT);
|
||||
printf("Waiting for client messages...\n\n");
|
||||
|
||||
/* Wait for client connection */
|
||||
cliLen = sizeof(cliAddr);
|
||||
recvLen = (int)recvfrom(listenfd, buf, sizeof(buf), MSG_PEEK,
|
||||
(struct sockaddr*)&cliAddr, &cliLen);
|
||||
if (recvLen < 0) {
|
||||
fprintf(stderr, "Error: recvfrom failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Connect UDP socket to client */
|
||||
ret = connect(listenfd, (struct sockaddr*)&cliAddr, cliLen);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error: UDP connect failed\n");
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Client connected from %s:%d\n",
|
||||
inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
|
||||
|
||||
/* Set DTLS peer */
|
||||
wolfSSL_dtls_set_peer(ssl, &cliAddr, cliLen);
|
||||
|
||||
/* Set socket file descriptor */
|
||||
wolfSSL_set_fd(ssl, listenfd);
|
||||
|
||||
/* Handle messages using the imported session */
|
||||
while (!cleanup) {
|
||||
recvLen = wolfSSL_read(ssl, buf, sizeof(buf) - 1);
|
||||
if (recvLen > 0) {
|
||||
buf[recvLen] = '\0';
|
||||
printf("Received: %s", (char*)buf);
|
||||
|
||||
/* Send acknowledgment */
|
||||
ret = wolfSSL_write(ssl, ack, (int)strlen(ack));
|
||||
if (ret > 0) {
|
||||
printf("Sent: %s", ack);
|
||||
}
|
||||
else {
|
||||
int err = wolfSSL_get_error(ssl, ret);
|
||||
fprintf(stderr, "Error: wolfSSL_write failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int err = wolfSSL_get_error(ssl, recvLen);
|
||||
if (err != SSL_ERROR_WANT_READ) {
|
||||
fprintf(stderr, "Error: wolfSSL_read failed: %d (%s)\n",
|
||||
err, wolfSSL_ERR_reason_error_string(err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (sessionBuf != NULL) free(sessionBuf);
|
||||
if (ssl != NULL) {
|
||||
wolfSSL_shutdown(ssl);
|
||||
wolfSSL_free(ssl);
|
||||
}
|
||||
if (listenfd > 0) close(listenfd);
|
||||
if (ctx != NULL) wolfSSL_CTX_free(ctx);
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
Loading…
Reference in New Issue