Alter ISO-TP example to use wolfSSL native

Uses the wolfSSL native ISO-TP instead of a third-party one.
pull/280/head
Andrew Hutchings 2021-12-24 11:54:33 +00:00
parent 7be7d7fa9e
commit ef0ee3649c
6 changed files with 63 additions and 212 deletions

3
.gitmodules vendored
View File

@ -16,6 +16,3 @@
[submodule "android/wolfcryptjni-ndk-gradle/wolfcrypt-jni"]
path = android/wolfcryptjni-ndk-gradle/wolfcrypt-jni
url = https://github.com/wolfssl/wolfcrypt-jni
[submodule "can-bus/isotp-c"]
path = can-bus/isotp-c
url = https://github.com/lishen2/isotp-c

View File

@ -1,16 +1,13 @@
CC=gcc
LIBS=-lwolfssl
CFLAGS=-Iisotp-c -Wno-cpp -Wall -Wextra -Wdeclaration-after-statement
CFLAGS=-g -Wno-cpp -Wall -Wextra -Wpedantic -Wdeclaration-after-statement
COMMON_OBJS=isotp-c/isotp.o common.o
COMMON_OBJS=common.o
CLIENT_OBJS=client.o
SERVER_OBJS=server.o
all: client server
isotp-c/isotp.o: isotp-c/isotp.c
@$(CC) -c $< -o $@
%.o: %.c
@$(CC) -c $< -o $@ $(CFLAGS)
@ -24,4 +21,3 @@ clean:
@rm -f *.o
@rm -f client
@rm -f server
@rm -f isotp-c/isotp.o

View File

@ -4,7 +4,7 @@ This example implements a simple echo client and server that uses TLS over a CAN
## Building
You need to have wolfSSL installed on your computer prior to building. If you haven't already you will also need to get the git submodules for this tree, you can do this by using `git submodule update --init`. A simple `make` will then build the source files.
You need to have wolfSSL installed on your computer prior to building, this will need to be built with `WOLFSSL_ISOTP` defined to provide ISO-TP functionality.
To generate the required SSL certificates use `./generate_ssl.sh`.
@ -13,7 +13,7 @@ To generate the required SSL certificates use `./generate_ssl.sh`.
If you do not have a physical CAN bus between too machines you can use the virtual CAN bus which is a Linux kernel module. This behaves just like a real CAN bus with a similar bandwidth. To enable this run the following commands:
```sh
modprobe vcan
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 up
```
@ -32,29 +32,9 @@ Then in another terminal run the client:
server vcan0
```
On the client you will see (byte numbers will vary):
On both ends you will see:
```
Sending 242 bytes
Receiving 128 bytes
Receiving 28 bytes
Receiving 974 bytes
Receiving 286 bytes
Receiving 58 bytes
Sending 58 bytes
SSL handshake done!
```
And on the server:
```
Receiving 242 bytes
Sending 128 bytes
Sending 28 bytes
Sending 974 bytes
Sending 286 bytes
Sending 58 bytes
Receiving 58 bytes
SSL handshake done!
```
@ -66,14 +46,12 @@ For example, on the client if we type "Hello world, this is a TLS test!":
Hello world! This is a CAN bus test!
Sending: Hello world! This is a CAN bus test!
Sending 59 bytes
Message sent
```
The server will echo:
```
Receiving 59 bytes
Got message: Hello world! This is a CAN bus test!
```

View File

@ -21,91 +21,68 @@
#include "common.h"
static int sock = -1;
volatile int keep_running = 1;
static uint8_t *copy_buf = NULL;
static uint8_t *copy_buf_ptr;
static size_t copy_buf_len;
static IsoTpLink g_link;
static isotp_wolfssl_ctx isotp_ctx;
/* Alloc send and receive buffer statically in RAM */
static uint8_t g_isotpRecvBuf[ISOTP_BUFSIZE];
static uint8_t g_isotpSendBuf[ISOTP_BUFSIZE];
struct can_info {
int sock;
canid_t arbitration;
canid_t remote_arbitration;
};
struct can_info can_con_info;
/* Function callback for wolfSSL to add delays to messages when a receiver
* requests it*/
void can_delay(int microseconds)
{
usleep(microseconds);
}
void sig_handle(int dummy);
/* Debug function required by ISO-TP to compile, can be blank */
void isotp_user_debug(const char* format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
printf("\r\n");
va_end(args);
}
/* Timing function required by ISO-TP to compile */
uint32_t isotp_user_get_ms(void) {
struct timeval t;
gettimeofday(&t, NULL);
return (t.tv_sec * 1000) + (t.tv_usec / 1000);
}
/* CAN bus send function require by ISO-TP to compile */
int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t* data,
const uint8_t size) {
/* Copy the message into a CAN bus frame, the message will always be
* 8 bytes or less */
struct can_frame frame;
frame.can_id = arbitration_id;
frame.can_dlc = size;
memcpy(frame.data, data, size);
/* Write the frame to the CAN bus */
if (write(sock, &frame, sizeof(struct can_frame))
!= sizeof(struct can_frame)) {
perror("Write error\n");
return -1;
}
return 0;
}
/* Our CAN bus receive function */
int can_receive(uint8_t data[CAN_MSG_LEN], int *length) {
/* Function callback for wolfSSL to send a CAN bus frame of up to 8 bytes */
int can_receive(struct isotp_can_data *data, void *arg, int timeout) {
int nbytes;
int ret;
struct can_info *info = ((struct can_info*)arg);
struct can_frame frame;
struct pollfd p[1];
p[0].fd = sock;
p[0].fd = info->sock;
p[0].events = POLLIN;
/* Poll for new data */
ret = poll(p, 1, 10);
ret = poll(p, 1, timeout);
if (ret < 0) {
perror("Poll error\n");
return 1;
}
else if (ret == 0) {
/* No data */
*length = 0;
return EAGAIN;
if (ret <= 0) {
return ret;
}
/* Read in the frame data */
nbytes = read(sock, &frame, sizeof(struct can_frame));
if (nbytes < 0) {
perror("Read error\n");
return 1;
nbytes = read(info->sock, &frame, sizeof(struct can_frame));
if (nbytes <= 0) {
return nbytes;
}
memcpy(data, frame.data, frame.can_dlc);
*length = frame.can_dlc;
return 0;
memcpy(data->data, frame.data, frame.can_dlc);
data->length = frame.can_dlc;
return ret;
}
/* Function callback for wolfSSL to send a CAN bus frame of up to 8 bytes */
int can_send(struct isotp_can_data *data, void *arg)
{
struct can_info *info = ((struct can_info*)arg);
struct can_frame frame;
memcpy(frame.data, data->data, data->length);
frame.can_dlc = data->length;
frame.can_id = info->arbitration;
return write(info->sock, &frame, sizeof(struct can_frame));
}
/* Connect to the CAN bus */
int can_connect(const char *address, uint16_t filter)
{
@ -114,12 +91,14 @@ int can_connect(const char *address, uint16_t filter)
/* Setup a CAN bus ID filter so that the kernel space filters out messages
* we don't need. This is faster than userspace doing it */
struct can_filter rfilter[1];
int sock = -1;
rfilter[0].can_id = filter;
rfilter[0].can_mask = 0xFFF;
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Socket open error\n");
return 1;
return -1;
}
/* Set the filter */
setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
@ -132,103 +111,15 @@ int can_connect(const char *address, uint16_t filter)
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Bind error\n");
return 1;
return -1;
}
/* Setup the receive copy buffer */
copy_buf = malloc(ISOTP_BUFSIZE);
copy_buf_ptr = copy_buf;
copy_buf_len = 0;
if (!copy_buf) {
fprintf(stderr, "Copy buf malloc fail\n");
return MEMORY_E;
}
return 0;
return sock;
}
void can_close()
{
free(copy_buf);
close(sock);
}
/* The wolfSSL send packet callback. This function sends the data via ISO-TP
* and then listens and processes the ISO-TP control packets until the message
* is completely sent */
int send_ssl(WOLFSSL *ssl, char *buf, int sz, void *ctx)
{
uint8_t data[CAN_MSG_LEN];
int length;
IsoTpLink *g_link = (struct IsoTpLink*)ctx;
int ret = isotp_send(g_link, (uint8_t*)buf, sz);
(void) ssl;
printf("Sending %d bytes\n", sz);
if (ret) {
fprintf(stderr, "Error from isotp: %d\n", ret);
return -64;
}
while(g_link->send_status != ISOTP_SEND_STATUS_IDLE) {
ret = can_receive(data, &length);
if (!ret && (length > 0)) {
/* Got a control frame */
isotp_on_can_message(g_link, data, length);
} else if (ret != EAGAIN) {
fprintf(stderr, "Receive error\n");
}
isotp_poll(g_link);
}
return sz;
}
/* Receive callback for wolfSSL. ISO-TP will only return a buffer once and it
* can be more data than wolfSSL wants, so we copy this into an intermediate
* buffer and just return what wolfSSL is asking for */
int recv_ssl(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
uint8_t data[CAN_MSG_LEN];
int data_len;
uint16_t msg_len = 0;
IsoTpLink *g_link = (struct IsoTpLink*)ctx;
(void) ssl;
if (!copy_buf_len) {
while (isotp_receive(g_link, copy_buf, ISOTP_BUFSIZE, &msg_len)
!= ISOTP_RET_OK) {
int ret = can_receive(data, &data_len);
if (ret == EAGAIN) {
return 0;
}
if (!ret && (data_len > 0)) {
isotp_on_can_message(g_link, data, data_len);
} else if (ret) {
fprintf(stderr, "Recieve error\n");
return -99;
}
}
if (msg_len) {
copy_buf_ptr = copy_buf;
printf("Receiving %d bytes\n", msg_len);
copy_buf_len = msg_len;
}
}
if (copy_buf_len >= (size_t)sz) {
memcpy(buf, copy_buf_ptr, sz);
copy_buf_ptr+= sz;
copy_buf_len-= sz;
return sz;
} else {
memcpy(buf, copy_buf_ptr, copy_buf_len);
sz = copy_buf_len;
copy_buf_len = 0;
return sz;
}
return msg_len;
close(can_con_info.sock);
}
void close_ssl(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
@ -261,21 +152,20 @@ void sig_handle(int dummy)
int setup_connection(const char *interface, int local_id, int remote_id)
{
int sock;
struct sigaction sa = { .sa_handler = sig_handle, /* .sa_flags = 0 */ };
sigaction(SIGINT, &sa, 0);
wolfSSL_Init();
/* Connect to CAN bus provided on command line, filter out everything
* except for the local CAN ID */
if (can_connect(interface, local_id)) {
* except for the remote CAN ID */
sock = can_connect(interface, remote_id);
if (sock < 1) {
return -1;
}
/* Setup ISO-TP and set the buffers */
isotp_init_link(&g_link, remote_id, g_isotpSendBuf,
sizeof(g_isotpSendBuf), g_isotpRecvBuf, sizeof(g_isotpRecvBuf));
can_con_info.sock = sock;
can_con_info.arbitration = local_id;
return 0;
}
@ -286,6 +176,7 @@ int setup_ssl(enum service_type type, WOLFSSL_CTX **new_ctx,
WOLFSSL_CTX *ctx = NULL;
WOLFSSL_METHOD* method = NULL;
WOLFSSL* ssl = NULL;
char *receive_buffer = malloc(ISOTP_DEFAULT_BUFFER_SIZE);
if (type == SERVICE_TYPE_CLIENT) {
method = wolfTLSv1_3_client_method();
@ -305,11 +196,6 @@ int setup_ssl(enum service_type type, WOLFSSL_CTX **new_ctx,
return -1;
}
/* Set the send and receive callback functions which will use the
* CAN bus */
wolfSSL_CTX_SetIOSend(ctx, send_ssl);
wolfSSL_CTX_SetIORecv(ctx, recv_ssl);
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
if (type == SERVICE_TYPE_CLIENT) {
@ -343,9 +229,8 @@ int setup_ssl(enum service_type type, WOLFSSL_CTX **new_ctx,
return -1;
}
/* Set the read and write context to both use the ISO-TP link */
wolfSSL_SetIOWriteCtx(ssl, &g_link);
wolfSSL_SetIOReadCtx(ssl, &g_link);
wolfSSL_SetIO_ISOTP(ssl, &isotp_ctx, can_receive, can_send, can_delay, 0,
receive_buffer, ISOTP_DEFAULT_BUFFER_SIZE, &can_con_info);
if (type == SERVICE_TYPE_CLIENT) {
ret = wolfSSL_connect(ssl);

View File

@ -37,13 +37,10 @@
#include <poll.h>
#include <signal.h>
#include <isotp.h>
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#define ISOTP_BUFSIZE 16384
#define CAN_MSG_LEN 8
#define ERR_MSG_LEN 80
@ -55,12 +52,11 @@ enum service_type {
SERVICE_TYPE_SERVER
};
int can_receive(uint8_t data[CAN_MSG_LEN], int *length);
int can_receive(struct isotp_can_data *data, void *arg, int timeout);
int can_send(struct isotp_can_data *data, void *arg);
int can_connect(const char *address, uint16_t filter);
void can_close(void);
int send_ssl(WOLFSSL *ssl, char *buf, int sz, void *ctx);
int recv_ssl(WOLFSSL* ssl, char *buf, int sz, void* ctx);
void close_ssl(WOLFSSL_CTX *ctx, WOLFSSL *ssl);
int setup_connection(const char *interface, int local_id, int remote_id);
int setup_ssl(enum service_type type, WOLFSSL_CTX **new_ctx,

@ -1 +0,0 @@
Subproject commit 9755e0390921b18f188a01978ac7f03233af68fd