/* depend: */
/* cflags: */
-/* linker: mapec.o */
+/* linker: mapec.o -lmorep */
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
+#include <morep/morep.h>
+#include <morep/pdu_clear_data.h>
+#include <morep/pdu_encrypted_data.h>
+
#include "mapec.h"
#include "verbose.h"
char *progname = NULL;
-char *version = "0.1";
+char *version = "0.9";
char *devtun = "tun://tun0:1440";
char *loctun = "tun://10.2.0.1";
char *remtun = "tun://10.2.1.0";
char *locudp = "udp://10.1.0.1:1234";
char *remudp = "udp://10.1.0.2:1235";
+char *cmblack = "";
+char *cmred = "";
int stop = 0;
DECLARE_VERBOSE_LEVEL (ulvpn, INFO);
+typedef struct {
+ uint8_t aad[4];
+ int red;
+ int black;
+} cm_t;
+
void sig_handler (int sig)
{
switch (sig) {
printf (" -u: remote udp (%s)\n", remudp);
printf (" -v: program verbose level [%d..%d] (%d)\n", ERROR, TRACE, GET_VERBOSE_LEVEL (ulvpn));
printf (" -V: library verbose level [%d..%d] (%d)\n", ERROR, TRACE, GET_VERBOSE_LEVEL (mapec));
+ printf (" -x: black CM service (%s)\n", cmblack);
+ printf (" -y: red CM service (%s)\n", cmred);
printf ("%s version %s\n", progname, version);
}
+int encrypt (uint8_t *buffer, int len, cm_t *cm)
+{
+
+ /* create clear message */
+ CLEAR_DATA_t msg = {0};
+ msg.channel_id = 0;
+ msg.bypass_len = 0;
+ memcpy (msg.aad + sizeof (msg.aad) - sizeof (cm->aad), cm->aad, sizeof (cm->aad));
+ int npad = 16 - (len % 16);
+ if (len + npad > (int)sizeof (msg.data)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("too long payload (%d)\n", len));
+ len = sizeof (msg.data) - 1;
+ npad = 1;
+ }
+ VERBOSE (ulvpn, DEBUG, PRINTF ("padding %d byte%s\n", npad, (npad > 1) ? "s" : ""));
+ memcpy (msg.data, buffer, len);
+ msg.data[len + npad - 1] = npad;
+ //memset (buffer, 0, len);
+ msg.data_len = len + npad;
+
+ /* serialize message and send it */
+ uint8_t out[MAXPAYLOAD] = {0};
+ int out_len = serial_clear_data (&msg, out, sizeof (out));
+ if (out_len < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when serializing clear message\n"));
+ return 0;
+ }
+ int seqtx = MOREP_Send (cm->red, 0x00, out, out_len);
+
+ /* get encrypted message and check it */
+ uint8_t in[MAXPAYLOAD] = {0};
+ uint8_t msgtype = 0;
+ int in_len = 0;
+ int seqrx = MOREP_Receive (cm->black, &msgtype, in, &in_len);
+ if ((msgtype != 0x01) || (in_len != out_len + 16) || (seqtx != seqrx)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent encrypyted message\n"));
+ return 0;
+ }
+ ENCRYPTED_DATA_t enc = {0};
+ if (!deserial_encrypted_data (in, in_len, &enc)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when deserializing encrypted message\n"));
+ return 0;
+ }
+
+ /* build output message */
+ len = 0;
+ //buf[len++] = enc.channel_id;
+ //check msg.bypass_len
+ memcpy (buffer + len, cm->aad, sizeof (cm->aad));
+ len += sizeof (cm->aad);
+ memcpy (buffer + len, enc.iv, sizeof (enc.iv));
+ len += sizeof (enc.iv);
+ memcpy (buffer + len, enc.data, enc.data_len);
+ len += enc.data_len;
+
+ return len;
+}
+
+int decrypt (uint8_t *buffer, int len, cm_t *cm)
+{
+
+ /* create encrypted message */
+ ENCRYPTED_DATA_t enc = {0};
+ int i = 0;
+ //if (i + 1 > len) {
+ // VERBOSE (ulvpn, WARNING, PRINTF ("no channel id\n");
+ // return 0;
+ //}
+ //enc.channel_id = buffer[i++];
+ enc.bypass_len = 0;
+ if (i + (int)sizeof (cm->aad) > len) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("incompleted aad\n"));
+ return 0;
+ }
+ memcpy (enc.aad + sizeof (enc.aad) - sizeof (cm->aad), buffer + i, sizeof (cm->aad));
+ i += sizeof (cm->aad);
+ if (i + (int)sizeof (enc.iv) > len) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("incompleted iv\n"));
+ return 0;
+ }
+ memcpy (enc.iv, buffer + i, sizeof (enc.iv));
+ i += sizeof (enc.iv);
+ if (len - i < 32) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("incompleted tag\n"));
+ return 0;
+ }
+ if ((len - i) % 16 != 0) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("incompleted encrypted message\n"));
+ return 0;
+ }
+ memcpy (enc.data, buffer + i, len - i);
+ enc.data_len = len - i;
+
+ /* serialize message and send it */
+ uint8_t out[MAXPAYLOAD] = {0};
+ int out_len = serial_encrypted_data (&enc, out, sizeof (out));
+ if (out_len < 0) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when serializing encrypted message\n"));
+ return 0;
+ }
+ int seqtx = MOREP_Send (cm->black, 0x02, out, out_len);
+
+ /* get clear message and check it */
+ uint8_t in[MAXPAYLOAD] = {0};
+ uint8_t msgtype = 0;
+ int in_len = 0;
+ int seqrx = MOREP_Receive (cm->red, &msgtype, in, &in_len);
+ if ((msgtype != 0x03) || (in_len != out_len - 16) || (seqtx != seqrx)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent decrypted message\n"));
+ return 0;
+ }
+ CLEAR_DATA_t msg = {0};
+ if (!deserial_clear_data (in, in_len, &msg)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("error when deserializing decrypted message\n"));
+ return 0;
+ }
+
+ /* build output message */
+ len = 0;
+ //buf[len++] = enc.channel_id;
+ //check msg.bypass_len
+ int npad = in[in_len - 1];
+ if ((npad > 16) || (msg.data_len < npad)) {
+ VERBOSE (ulvpn, WARNING, PRINTF ("non-coherent padding (%d)\n", npad));
+ return 0;
+ }
+ memcpy (buffer + len, enc.data, enc.data_len - npad);
+ len += enc.data_len - npad;
+
+ return len;
+}
+
int main (int argc, char **argv)
{
}
CHANGE_VERBOSE_LEVEL (mapec, atoi (arg));
break;
+ case 'x':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("%s: black cm service not specified\n", progname));
+ return 1;
+ }
+ cmblack = arg;
+ break;
+ case 'y':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ VERBOSE (ulvpn, ERROR, PRINTF ("%s: red cm service not specified\n", progname));
+ return 1;
+ }
+ cmred = arg;
+ break;
case 'h':
default:
usage ();
return -1;
}
+ /* init crypto module */
+ cm_t cm = {{0, 0, 0, 0}, -1, -1};
+ if ((cmblack) && (*cmblack)) {
+ cm.black = MOREP_Connect (cmblack);
+ }
+ if ((cmred) && (*cmred)) {
+ cm.red = MOREP_Connect (cmred);
+ }
+ int cmok = (cm.black >= 0) && (cm.red >= 0);
+ if (!cmok) {
+ VERBOSE (ulvpn, INFO, PRINTF ("CM desactivated\n"));
+ }
+
/* signals */
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
} else {
VERBOSE (ulvpn, DEBUG, PRINTF ("received from tun %d bytes\n", r));
- //encrypt it
+ if (cmok) {
+ r = encrypt (buffer, r, &cm);
+ }
r = MAPEC_Send (udp_fd, buffer, r);
if (r < 0) {
} else {
VERBOSE (ulvpn, DEBUG, PRINTF ("received from udp %d bytes\n", r));
- //decrypt it
+ if (cmok) {
+ r = decrypt (buffer, r, &cm);
+ }
r = MAPEC_Send (tun_fd, buffer, r);
if (r < 0) {
}
/* test: ulvpn.exe -h | grep usage */
-/* test: chmod a+w *.gcda */
/* test: ulvpn.exe help 2>&1 | grep usage */
/* test: ulvpn.exe -d 2>&1 | grep 'dev tun not specified' */
/* test: ulvpn.exe -l 2>&1 | grep 'local tun not specified' */
/* test: ulvpn.exe -u 2>&1 | grep 'remote udp not specified' */
/* test: ulvpn.exe -v 2>&1 | grep 'verbose level not specified' */
/* test: ulvpn.exe -V 2>&1 | grep 'verbose level not specified' */
+/* test: ulvpn.exe -x 2>&1 | grep 'black cm service not specified' */
+/* test: ulvpn.exe -y 2>&1 | grep 'red cm service not specified' */
/* test: sudo -u `awk -F: '/sh$/ && $3 != 0 {print $1; exit}' /etc/passwd` ulvpn.exe; test $? -ne 0 */