From 07eb16a0eb8a7b8d991891f11328c8524091ea4e Mon Sep 17 00:00:00 2001 From: Mazet Laurent Date: Tue, 8 Apr 2025 04:40:41 +0200 Subject: [PATCH] add simulator --- makefile | 1 + morep_simulator.c | 443 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 morep_simulator.c diff --git a/makefile b/makefile index ca628ca..b9784bf 100644 --- a/makefile +++ b/makefile @@ -42,6 +42,7 @@ endif ALLEXE = ALLEXE += morep_test ALLEXE += morep_valid +ALLEXE += morep_simulator SHELL = bash diff --git a/morep_simulator.c b/morep_simulator.c new file mode 100644 index 0000000..a19c13b --- /dev/null +++ b/morep_simulator.c @@ -0,0 +1,443 @@ +/* + File name : morep_simulator.c + Projet : MERLIN + Date of creation : 2025/04/09 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : MOREP simulator + + History : + - initial version +*/ + +/* depend: */ +/* cflags: */ +/* linker: morep.o parse.o pdu_channel.o pdu_encrypted_data.o pdu_prng_param.o pdu_status.o pdu_clear_data.o pdu_key.o pdu_raw_data.o */ +/* winlnk: morep.o parse.o pdu_channel.o pdu_encrypted_data.o pdu_prng_param.o pdu_status.o pdu_clear_data.o pdu_key.o pdu_raw_data.o */ + +#include +#include +#include +#include +#include +#include +#include + +#include "morep.h" +#include "parse.h" +#include "verbose.h" + +#include "pdu_channel.h" +#include "pdu_encrypted_data.h" +#include "pdu_prng_param.h" +#include "pdu_status.h" +#include "pdu_clear_data.h" +#include "pdu_key.h" +#include "pdu_raw_data.h" +#include "pdu_raw_data.h" + +char *progname = NULL; + +int stop = 0; + +DECLARE_VERBOSE_LEVEL (morep, INFO); + +#define BUFMAX 4096 + +typedef enum { + nomod_e = 0, + red_e, + cryp_e, + black_e +} module_t; + +typedef enum { + noserv_e = 0, + bypass_e, + control_e, + cross_crypto_e, + local_crypto_e, + prng_e, + provisioning_e +} service_t; + +typedef enum { + nopdu_e = 0, + channel_e, + clear_data_e, + encrypted_data_e, + key_e, + prng_param_e, + raw_data_e, + status_e +} pdu_t; + +typedef struct { + char *name; + service_t service; + uint8_t msgtype; + pdu_t pdu; +} message_t; + +message_t message_list[] = { + + /* Cross cryptographic service */ + {"ENCRYPT_CROSS_ASYNC", cross_crypto_e, 0x00, clear_data_e}, + {"ENCRYPTED_CROSS_ASYNC", cross_crypto_e, 0x01, encrypted_data_e}, + {"DECRYPT_CROSS_ASYNC", cross_crypto_e, 0x02, encrypted_data_e}, + {"DECRYPTED_CROSS_ASYNC", cross_crypto_e, 0x03, clear_data_e}, + + /* Local cryptographic service */ + {"ENCRYPT_LOCAL_ASYNC", local_crypto_e, 0x00, clear_data_e}, + {"ENCRYPTED_LOCAL_ASYNC", local_crypto_e, 0x01, encrypted_data_e}, + {"DECRYPT_LOCAL_ASYNC", local_crypto_e, 0x02, encrypted_data_e}, + {"DECRYPTED_LOCAL_ASYNC", local_crypto_e, 0x03, clear_data_e}, + + /* Provisioning service */ + {"LOAD_KEY_REQ", provisioning_e, 0x00, key_e}, + {"LOAD_KEY_RESP", provisioning_e, 0x01, status_e}, + {"UNLOAD_KEY_REQ", provisioning_e, 0x02, key_e}, + {"UNLOAD_KEY_RESP", provisioning_e, 0x03, status_e}, + {"ERASE_KEY_REQ", provisioning_e, 0x04, key_e}, + {"ERASE_KEY_RESP", provisioning_e, 0x05, status_e}, + {"ASSOCIATE_CHANNEL_REQ", provisioning_e, 0x06, channel_e}, + {"ASSOCIATE_CHANNEL_RESP", provisioning_e, 0x07, status_e}, + {"DISSOCIATE_CHANNEL_REQ", provisioning_e, 0x08, channel_e}, + {"DISSOCIATE_CHANNEL_RESP", provisioning_e, 0x09, status_e}, + + /* Bypass service */ + {"BYPASS_CROSS_ASYNC", bypass_e, 0x00, raw_data_e}, + {"BYPASSED_CROSS_ASYNC", bypass_e, 0x01, raw_data_e}, + + /* Control service */ + {"STATUS_REQ", control_e, 0x00, nopdu_e}, + {"STATUS_RESP", control_e, 0x01, status_e}, + {"AUTHENTIFICATION_REQ", control_e, 0x02, raw_data_e}, + {"AUTHENTIFICATION_RESP", control_e, 0x03, raw_data_e}, + {"REBOOT_REQ", control_e, 0x04, nopdu_e}, + {"REBOOT_RESP", control_e, 0x05, status_e}, + {"ZEROIZE_REQ", control_e, 0x04, nopdu_e}, + {"ZEROIZE_RESP", control_e, 0x05, status_e}, + {"LOCK_REQ", control_e, 0xFE, nopdu_e}, + {"LOCK_RESP", control_e, 0xFF, status_e} +} + +void sig_handler (int sig) +{ + switch (sig) { + case SIGINT: + //stop = 1; + exit (0); + break; + case SIGTERM: + exit (0); + break; + } +} + +char *read_stream (FILE *sd, int *plen) +{ + VERBOSE (morep, TRACE, PRINTF ("read_stream\n")); + + /* read and store */ + char *buffer = NULL; + size_t size = 0; + int blocklen = 0; + int length = 0; + do { + size += BUFMAX + (size == 0); + buffer = (char *) realloc (buffer, size); + memset (buffer + size - BUFMAX - 1, 0, BUFMAX + 1); + blocklen = fread (buffer + size - BUFMAX - 1, 1, BUFMAX, sd); + length += blocklen; + } while (blocklen > 0); + + /* check size */ + VERBOSE (morep, DEBUG, PRINTF ("read length: %d\n", length)); + if (length == 0) { + free (buffer); + buffer = NULL; + } + + if (plen) { + *plen = length; + } + + return buffer; +} + +void print_message (FILE *fd, char *etype, int mode, uint8_t msg, int seqnum, uint8_t *payload, int len) +{ + fprintf (fd ? fd : stdout, "%c%s SEG=%d MSG=%d LEN=%d", mode ? 'T' : 'R', etype, seqnum, msg, len); + if (len > 0) { + int i; + fprintf (fd ? fd : stdout, " PAYLOAD="); + for (i = 0; i < len; i++) { + fprintf (fd, "%02x", payload[i]); + } + } + fprintf (fd ? fd : stdout, "\n"); +} + +typedef struct { + int morep; + int mode; + char *etype; +} comm_t; + +#define MAXCOMMS 32 + +int main (int argc, char **argv) +{ + char *filename = NULL; + char *logname = NULL; + char *url = NULL; + int mode = -1; + int nbcomms = 0; + comm_t comm_list[MAXCOMMS] = {0}; + + /* get basename */ + char *ptr = progname = argv[0]; + while (*ptr) { + if ((*ptr == '/') || (*ptr == '\\')) { + progname = ptr + 1; + } + ptr++; + } + + /* process argument */ + while (argc-- > 1) { + char *arg = *(++argv); + if (arg[0] != '-') { + filename = arg; + continue; + } + char c = arg[1]; + switch (c) { + case 'l': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (morep, ERROR, PRINTF ("%s: log file not specified\n", progname)); + return 1; + } + logname = arg; + break; + case 'r': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (morep, ERROR, PRINTF ("%s: receiver url not specified\n", progname)); + return 1; + } + url = arg; + mode = 0; + break; + case 't': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (morep, ERROR, PRINTF ("%s: transmitter url not specified\n", progname)); + return 1; + } + url = arg; + mode = 1; + break; + case 'v': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (morep, ERROR, PRINTF ("%s: verbose level not specified\n", progname)); + return 1; + } + CHANGE_VERBOSE_LEVEL (morep, atoi (arg)); + break; + case 'h': + default: + printf ("usage: %s [-h] [-l log] [-r url] [-t url] [-v level] [file]\n", progname); + return (c != 'h'); + } + + /* init communication channel */ + if (mode != -1) { + if (nbcomms < MAXCOMMS) { + int morep = MOREP_Connect (url); + if (morep >= 0) { + (comm_list + nbcomms)->morep = morep; + (comm_list + nbcomms)->mode = mode; + (comm_list + nbcomms)->etype = strrchr (url, '/') + 1; + nbcomms++; + } else { + VERBOSE (morep, ERROR, PRINTF ("can't connect on url '%s'\n", url)); + return -1; + } + } else { + VERBOSE (morep, ERROR, PRINTF ("no more communication channel avaliable (%d)\n", nbcomms)); + return -1; + } + mode = -1; + } + } + + /* checks */ + if (nbcomms == 0) { + VERBOSE (morep, ERROR, PRINTF ("no communication channel\n")); + return -1; + } + + /* open script file */ + FILE *fid = stdin; + if (filename != NULL) { + fid = fopen (filename, "r"); + if (fid == NULL) { + VERBOSE (morep, ERROR, PRINTF ("can't open script file '%s' for reading\n", filename)); + return -1; + } + } + char *script = read_stream (fid, NULL); + if (fid != stdin) { + fclose (fid); + } + if (script == NULL) { + VERBOSE (morep, ERROR, PRINTF ("no script read\n")); + return -1; + } + + /* open log file */ + FILE *log = NULL; + if (logname != NULL) { + if (strcmp (logname, "-") == 0) { + log = stdout; + } else { + log = fopen (logname, "w"); + if (log == NULL) { + VERBOSE (morep, ERROR, PRINTF ("can't open log file '%s' for writing\n", logname)); + return -1; + } + } + } + + /* signals */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + /* main loop */ + int rc = 0; + ptr = script; + while (*ptr != '\0') { + + /* read line */ + char *line = ptr; + TEST_CHARS (ptr, "\n\r", 1); + *ptr++ = '\0'; + + /* clean line */ + TEST_CHARS (line, " \t", 0); + if ((*line == '\0') || (*line == '#')) { + continue; + } + + /* analyse line */ + mode = -1; + if (*line == 'R') { + mode = 0; + } else if (*line == 'T') { + mode = 1; + } else if (strncmp (line, "SLEEP", 5) == 0) { + int duration = atoi (line + 5); + VERBOSE (morep, INFO, PRINTF ("sleep %dms\n", duration)); + usleep (duration * 1000); + continue; + } + if (mode == -1) { + VERBOSE (morep, WARNING, PRINTF ("unrecognize line '%s'\n", line)); + continue; + } + + /* find ethertype */ + comm_t *comm = NULL; + int offset = 1; + int i; + for (i = 0; i < nbcomms; i++) { + comm_t *c = comm_list + i; + VERBOSE (morep, TRACE, PRINTF ("test %c[%s]\n", c->mode ? 'T' : 'R', c->etype)); + if ((strncmp (line + offset, c->etype, strlen (c->etype)) == 0) && (c->mode == mode)) { + comm = c; + offset += strlen (c->etype); + break; + } + } + if (comm == NULL) { + VERBOSE (morep, TRACE, PRINTF ("no morep found '%s'\n", line)); + continue; + } + VERBOSE (morep, DEBUG, PRINTF ("work with %c[%s]\n", comm->mode ? 'T' : 'R', comm->etype)); + + /* get values */ + char *tmp = line + offset; + uint8_t msgtype; + TEST_CHARS (tmp, " \t", 0); + if (strncmp (tmp, "MSG", 3) != 0) { + VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s' (%s)\n", line, tmp)); + continue; + } + tmp += 3; + TEST_CHARS (tmp, " \t=", 0); + msgtype = strtol (tmp, &tmp, 0); + if ((*tmp != ' ') && (*tmp != '\t')) { + VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s'\n", line)); + continue; + } + + RAW_DATA_t payload = {0}; + if (parse_raw_data (tmp, &payload) != 0) { + VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s'\n", line)); + continue; + } + VERBOSE (morep, TRACE, PRINTF ("payload length: %d\n", payload.data_len)); + + /* transmit */ + if (mode == 1) { + int seqnum = MOREP_Send (comm->morep, msgtype, payload.data, payload.data_len); + if (log) { + print_message (log, comm->etype, 1, msgtype, seqnum, payload.data, payload.data_len); + } + } else { /* receive */ + uint8_t rxmsgtype = 0; + uint8_t rxpayload[1496 * 16 - 1] = {0}; + int rxlen = -1; + int seqnum = MOREP_Receive (comm->morep, &rxmsgtype, rxpayload, &rxlen); + + /* check msg type */ + if (rxmsgtype != msgtype) { + VERBOSE (morep, WARNING, PRINTF ("R%sx SEQ=%d MSG=%d: expected msgtype %d\n", comm->etype, seqnum, rxmsgtype, msgtype)); + } + /* check payload */ + else if ((rxlen != payload.data_len) || + ((memcmp (rxpayload, payload.data, rxlen) != 0))) { + VERBOSE (morep, WARNING, PRINTF ("R%s SEQ=%d MSG=%d: payloads differed %d/%d\n", comm->etype, seqnum, rxmsgtype, payload.data_len, rxlen)); + } + if (log) { + print_message (log, comm->etype, 0, rxmsgtype, seqnum, rxpayload, rxlen); + } + } + } + + /* cleaning */ + free (script); + while (nbcomms) { + MOREP_Close (--nbcomms); + } + if ((log) && (log != stdout)) { + fclose (log); + } + + return rc; +} + +/* test: morep_valid.exe -h | grep usage */ +/* test: morep_valid.exe -r 2>&1 | grep 'url not specified' */ +/* test: morep_valid.exe -t 2>&1 | grep 'url not specified' */ +/* test: morep_valid.exe -l 2>&1 | grep 'log file not specified' */ +/* test: morep_valid.exe -l - -t lo://00:00:00:00:00:00/0808 -v 4 script-lo.eth */ +/* test: morep_valid.exe -l script.log -t lo://00:00:00:00:00:00/0808 -r lo://00:00:00:00:00:00/0808 script-lo.eth */ + +/* vim: set ts=4 sw=4 si et: */ -- 2.30.2