add simulator
authorMazet Laurent <laurent.mazet@thalesgroup.com>
Tue, 8 Apr 2025 02:40:41 +0000 (04:40 +0200)
committerMazet Laurent <laurent.mazet@thalesgroup.com>
Tue, 8 Apr 2025 02:40:41 +0000 (04:40 +0200)
makefile
morep_simulator.c [new file with mode: 0644]

index ca628ca0084dc86c733778417bbb56f82e0d26d5..b9784bf554d479e4bbeafd18d5025304627c8706 100644 (file)
--- 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 (file)
index 0000000..a19c13b
--- /dev/null
@@ -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 <laurent.mazet@thalesgroup.com>
+
+  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 <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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: */