This patch adds a queue to the config structure to house the security 
association
database and the necessary functions to copy information (spps, keys, etc) from 
a
security associations file into the security association database. Although 
these
functions are similar to those found in config.c, it is important the keys are
stored in a separate file from the rest of the config, thus all processing is 
done
in sad.c

Signed-off-by: Clay Kaiser <clay.kai...@ibm.com>
---
 config.c      |   2 +
 config.h      |   3 +
 makefile      |   7 +-
 ptp4l.c       |   6 +
 sad.c         | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sad.h         |  53 +++++++
 sad_private.h |  69 +++++++++
 7 files changed, 514 insertions(+), 3 deletions(-)
 create mode 100644 sad.c
 create mode 100644 sad.h
 create mode 100644 sad_private.h

diff --git a/config.c b/config.c
index b104f1b..8150dc7 100644
--- a/config.c
+++ b/config.c
@@ -364,6 +364,7 @@ struct config_item config_tab[] = {
        GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
        GLOB_ITEM_INT("verbose", 0, 0, 1),
        GLOB_ITEM_INT("write_phase_mode", 0, 0, 1),
+       GLOB_ITEM_STR("sa_file", NULL),
 };
 
 static struct unicast_master_table *current_uc_mtab;
@@ -918,6 +919,7 @@ struct config *config_create(void)
        }
        STAILQ_INIT(&cfg->interfaces);
        STAILQ_INIT(&cfg->unicast_master_tables);
+       STAILQ_INIT(&cfg->security_association_database);
 
        cfg->opts = config_alloc_longopts();
        if (!cfg->opts) {
diff --git a/config.h b/config.h
index 14d2f64..6915c85 100644
--- a/config.h
+++ b/config.h
@@ -45,6 +45,9 @@ struct config {
 
        /* unicast master tables */
        STAILQ_HEAD(ucmtab_head, unicast_master_table) unicast_master_tables;
+
+       /* security association database */
+       STAILQ_HEAD(sa_head, security_association) 
security_association_database;
 };
 
 int config_read(const char *name, struct config *cfg);
diff --git a/makefile b/makefile
index 3e3b8b3..581cca4 100644
--- a/makefile
+++ b/makefile
@@ -23,6 +23,7 @@ VER     = -DVER=$(version)
 CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
 LDLIBS = -lm -lrt -pthread $(EXTRA_LDFLAGS)
 PRG    = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc tz2alt
+SECURITY = sad.o
 FILTERS        = filter.o mave.o mmedian.o
 SERVOS = linreg.o ntpshm.o nullf.o pi.o refclock_sock.o servo.o
 TRANSP = raw.o transport.o udp.o udp6.o uds.o
@@ -30,9 +31,9 @@ TS2PHC        = ts2phc.o lstab.o nmea.o serial.o sock.o 
ts2phc_generic_pps_source.o \
  ts2phc_nmea_pps_source.o ts2phc_phc_pps_source.o ts2phc_pps_sink.o 
ts2phc_pps_source.o
 OBJ    = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
  e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \
- port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \
- sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.o \
- unicast_fsm.o unicast_service.o util.o version.o
+ port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SECURITY) \
+ $(SERVOS) sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o 
unicast_client.o \
+ unicast_fsm.o unicast_service.o util.o version.o 
 
 OBJECTS        = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o 
pmc_agent.o \
  pmc_common.o sysoff.o timemaster.o $(TS2PHC) tz2alt.o
diff --git a/ptp4l.c b/ptp4l.c
index c61175b..58c26b7 100644
--- a/ptp4l.c
+++ b/ptp4l.c
@@ -29,6 +29,7 @@
 #include "pi.h"
 #include "print.h"
 #include "raw.h"
+#include "sad.h"
 #include "sk.h"
 #include "transport.h"
 #include "udp6.h"
@@ -192,6 +193,10 @@ int main(int argc, char *argv[])
        sk_tx_timeout = config_get_int(cfg, NULL, "tx_timestamp_timeout");
        sk_hwts_filter_mode = config_get_int(cfg, NULL, "hwts_filter");
 
+       if (sad_create(cfg)) {
+               goto out;
+       }
+
        if (config_get_int(cfg, NULL, "clock_servo") == CLOCK_SERVO_NTPSHM) {
                config_set_int(cfg, "kernel_leap", 0);
                config_set_int(cfg, "sanity_freq_limit", 0);
@@ -255,6 +260,7 @@ int main(int argc, char *argv[])
 out:
        if (clock)
                clock_destroy(clock);
+       sad_destroy(cfg);
        config_destroy(cfg);
        return err;
 }
diff --git a/sad.c b/sad.c
new file mode 100644
index 0000000..b6ee416
--- /dev/null
+++ b/sad.c
@@ -0,0 +1,377 @@
+/**
+ * @file sad.c
+ * @brief Security Association Database
+ *
+ * This program 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.
+ *
+ * This program 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.
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "msg.h"
+#include "print.h"
+#include "sad.h"
+#include "sad_private.h"
+#include "tlv.h"
+
+static struct security_association *current_sa;
+static struct integrity_alg_info supported_algorithms [] = {
+       { "SHA256-128", HMAC_SHA256_128, 16 },
+       { "SHA256",     HMAC_SHA256,     32 },
+       { "AES128",     CMAC_AES128,     16 },
+       { "AES256",     CMAC_AES256,     16 },
+       { NULL, 0, 0 },
+};
+
+static void sad_destroy_association(struct security_association *sa)
+{
+       struct security_association_key *key;
+       while ((key = STAILQ_FIRST(&sa->keys))) {
+               STAILQ_REMOVE_HEAD(&sa->keys, list);
+               sad_deinit_mac(key->data);
+               free(key);
+       }
+}
+
+void sad_destroy(struct config *cfg)
+{
+       struct security_association *sa;
+       while ((sa = STAILQ_FIRST(&cfg->security_association_database))) {
+               sad_destroy_association(sa);
+               STAILQ_REMOVE_HEAD(&cfg->security_association_database, list);
+               free(sa);
+       }
+}
+
+static int sad_config_switch_security_association(struct config *cfg,
+                                                 int spp, int line_num)
+{
+       struct security_association *sa;
+       current_sa = NULL;
+
+       if (spp < 0 || spp > UINT8_MAX) {
+               pr_err("sa_file: line %d: spp %d is out of range. "
+                       "Must be in the range %d to %d - ignoring",
+                       line_num, spp, 0, UINT8_MAX);
+               return -1;
+       }
+       STAILQ_FOREACH(sa, &cfg->security_association_database, list) {
+               if (sa->spp == spp) {
+                       pr_err("line %d: sa %d already taken"
+                               " - ignoring", line_num, spp);
+                       return -1;
+               }
+       }
+       sa = calloc(1, sizeof(*sa));
+       if (!sa) {
+               pr_err("low memory");
+               return -1;
+       }
+       STAILQ_INIT(&sa->keys);
+       sa->spp = spp;
+       /* set defaults */
+       sa->seqnum_ind = 0;
+       sa->seqnum_len = 0;
+       sa->seqid_window = 3;
+       sa->immediate_ind = 1;
+       sa->res_ind = 0;
+       sa->res_len = 0;
+       sa->mutable = 0;
+       sa->last_seqid = 0;
+
+       STAILQ_INSERT_TAIL(&cfg->security_association_database, sa, list);
+       current_sa = sa;
+
+       return 0;
+}
+
+static int sad_config_sa_seqnum_len(int seqnum_len, int line_num)
+{
+       if (!current_sa) {
+               pr_err("sa_file: line %d: missing spp - ignoring",
+                       line_num);
+               return -1;
+       }
+
+       if (seqnum_len > 0) {
+               pr_err("sa_file: line %d: seqnum field not supported (yet)"
+                       " - ignoring", line_num);
+               return -1;
+       }
+
+       current_sa->seqnum_len = seqnum_len;
+       current_sa->seqnum_ind = (seqnum_len > 0) ? 1 : 0;
+
+       return 0;
+}
+
+static int sad_config_sa_seqid_window(int seqid_window, int line_num)
+{
+       if (!current_sa) {
+               pr_err("sa_file: line %d: missing spp - ignoring",
+                       line_num);
+               return -1;
+       }
+
+       if (seqid_window < 0 || seqid_window > UINT16_MAX / 2) {
+               pr_err("sa_file: line %d: seqid_window %d out of range"
+                       " - ignoring", line_num, seqid_window);
+               return -1;
+       }
+
+       current_sa->seqid_window = seqid_window;
+
+       return 0;
+}
+
+static int sad_config_sa_res_len(int res_len, int line_num)
+{
+       if (!current_sa) {
+               pr_err("sa_file: line %d: missing spp - ignoring",
+                       line_num);
+               return -1;
+       }
+
+       if (res_len > 0) {
+               pr_err("sa_file: line %d: res field not supported (yet)"
+                       " - ignoring", line_num);
+               return -1;
+       }
+
+       current_sa->res_len = res_len;
+       current_sa->res_ind = (res_len > 0) ? 1 : 0;
+
+       return 0;
+}
+
+static int sad_config_sa_mutable(int mutable, int line_num)
+{
+       if (!current_sa) {
+               pr_err("sa_file: line %d: missing spp - ignoring",
+                       line_num);
+               return -1;
+       }
+
+       if (mutable < 0 || mutable > 1) {
+               pr_err("sa_file: line %d: allow_mutable must be 0 or 1"
+                       " - ignoring", line_num);
+               return -1;
+       }
+
+       current_sa->mutable = (mutable > 0) ? 1 : 0;
+
+       return 0;
+}
+
+static int sad_config_parse_key(char *line, UInteger32 *id,
+                               const char **type, char **key)
+{
+       char *token, *tokens[4];
+       int count = 0;
+
+       token = strtok(line, " ");
+       while (token != NULL && count < 4) {
+               tokens[count] = token;
+               count++;
+               token = strtok(NULL, " ");
+       }
+       if (count < 2 || count > 3) {
+               return 0;
+       }
+
+       if (sscanf(tokens[0], "%u", id) != 1) {
+               return 0;
+       }
+       if (count == 2) {
+               *type = "SHA256-128";
+               *key = tokens[1];
+       } else {
+               *type = tokens[1];
+               *key = tokens[2];
+       }
+
+       return 1;
+}
+
+static int sad_config_security_association_key(UInteger32 key_id, const char 
*icv_str,
+                                              char *key_str, int line_num)
+{
+       struct security_association_key *key;
+       struct integrity_alg_info *icv;
+       int key_len = 0;
+
+       if (!current_sa) {
+               pr_err("sa_file: line %d: missing spp - ignoring",
+                       line_num);
+               return -1;
+       }
+       STAILQ_FOREACH(key, &current_sa->keys, list) {
+               if (key->key_id == key_id) {
+                       pr_err("sa_file: line %d: key_id %u already taken"
+                               " - ignoring", line_num, key_id);
+                       return -1;
+               }
+       }
+       key = calloc(1, sizeof(*key));
+       if (!key) {
+               pr_err("low memory");
+               free(key);
+               return -1;
+       }
+       /* process key_id */
+       if (key_id < 1 || key_id >= UINT32_MAX) {
+               pr_err("sa_file: line %d: key_id %u out of range"
+                       " - ignoring", line_num, key_id);
+               free(key);
+               return -1;
+       }
+       key->key_id = key_id;
+       /* process icv_str */
+       for (icv = supported_algorithms; icv->label; icv++) {
+               if (!strcasecmp(icv->label, icv_str)) {
+                       key->icv = *icv;
+                       break;
+               }
+       }
+       if (icv->label == NULL) {
+               pr_err("sa_file: line %d: unsupported algorithm: %s"
+                       " - ignoring", line_num, icv_str);
+               free(key);
+               return -1;
+       }
+       /* process key_str */
+       key_len = strlen(key_str);
+       if (strncmp(key_str, "ASCII:", 6) == 0) {
+               memmove(key_str, key_str + 6, key_len - 6);
+               key_len = key_len - 6;
+       } else if (strncmp(key_str, "HEX:", 4) == 0) {
+               memmove(key_str, key_str + 4, key_len - 4);
+               key_len = key_len - 4;
+               if (key_len % 2) {
+                       pr_err("sa_file: line %d: invalid key length"
+                               " - ignoring", line_num);
+                       free(key);
+                       return -1;
+               }
+               for (int i = 0; i < key_len; i += 2) {
+                       char hex_pair[3] = { key_str[i], key_str[i + 1], '\0' };
+                       long value = strtol(hex_pair, NULL, 16);
+                       key_str[i / 2] = (char)value;
+               }
+               key_len = key_len / 2;
+               memset(&key_str[key_len], 0, key_len);
+               key_str[key_len] = '\0';
+       }
+       /* initialize mac function */
+       key->data = sad_init_mac(icv->type, (unsigned char *) key_str, key_len);
+       if (key->data == NULL) {
+               pr_err("sa_file: line %d: key %u init failed"
+                       " - ignoring", line_num, key_id);
+               free(key);
+               return -1;
+       }
+       memset(&key_str, 0, key_len);
+
+       STAILQ_INSERT_TAIL(&current_sa->keys, key, list);
+
+       return 0;
+}
+
+static int sad_parse_security_association_line(struct config *cfg,
+                                               char *line, int line_num)
+{
+       int spp, seqnum_len, seqid_window, res_len, mutable;
+       UInteger32 key_id;
+       char *key_value;
+       const char *key_type;
+
+       if (sscanf(line, " spp %d", &spp) == 1)
+               return sad_config_switch_security_association(cfg, spp, 
line_num);
+
+       if (sscanf(line, " seqnum_length %d", &seqnum_len) == 1)
+               return sad_config_sa_seqnum_len(seqnum_len, line_num);
+
+       if (sscanf(line, " seqid_window %d", &seqid_window) == 1)
+               return sad_config_sa_seqid_window(seqid_window, line_num);
+
+       if (sscanf(line, " res_length %d", &res_len) == 1)
+               return sad_config_sa_res_len(res_len, line_num);
+
+       if (sscanf(line, " allow_mutable %d", &mutable) == 1)
+               return sad_config_sa_mutable(mutable, line_num);
+
+       if (sad_config_parse_key(line, &key_id, &key_type, &key_value))
+               return sad_config_security_association_key(key_id, key_type,
+                                                          key_value, line_num);
+
+       return 0;
+}
+
+int sad_create(struct config *cfg)
+{
+       char buf[1024], *line, *c;
+       int line_num;
+
+       const char *sa_file = config_get_string(cfg, NULL, "sa_file");
+       if (sa_file == NULL || strlen(sa_file) == 0) {
+               return 0;
+       }
+
+       FILE *fp = fopen(sa_file, "r");
+       if (!fp) {
+               pr_err("failed to open sa_file %s: %m", sa_file);
+               return -1;
+       }
+
+       /* destroy current sad if already configured */
+       sad_destroy(cfg);
+
+       for (line_num = 1; fgets(buf, sizeof(buf), fp); line_num++) {
+               c = buf;
+               /* skip whitespace characters */
+               while (isspace(*c))
+                       c++;
+               /* ignore empty lines and comments */
+               if (*c == '#' || *c == '\n' || *c == '\0')
+                       continue;
+
+               line = c;
+               /* remove trailing whitespace characters and \n */
+               c += strlen(line) - 1;
+               while (c > line && (*c == '\n' || isspace(*c))) {
+                       *c-- = '\0';
+               }
+               if (!strcasecmp(line, "[security_association]")) {
+                       current_sa = NULL;
+                       continue;
+               }
+               /* remove associated sa and continue if a config line fails */
+               if (sad_parse_security_association_line(cfg, line, line_num)) {
+                       if (current_sa != NULL) {
+                               pr_debug("discarding sa %u", current_sa->spp);
+                               sad_destroy_association(current_sa);
+                               
STAILQ_REMOVE(&cfg->security_association_database,
+                                               current_sa, 
security_association, list);
+                               free(current_sa);
+                               current_sa = NULL;
+                       }
+                       continue;
+               }
+       }
+
+       fclose(fp);
+       return 0;
+}
diff --git a/sad.h b/sad.h
new file mode 100644
index 0000000..a6b647d
--- /dev/null
+++ b/sad.h
@@ -0,0 +1,53 @@
+/**
+ * @file sad.h
+ * @brief Security Association Database
+ *
+ * This program 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.
+ *
+ * This program 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.
+ */
+#ifndef HAVE_SAD_H
+#define HAVE_SAD_H
+
+#include <sys/queue.h>
+
+#include "pdt.h"
+
+struct security_association {
+       STAILQ_ENTRY(security_association) list;
+       UInteger8       spp;           /* negotiated by key management (see 
3.1.68). */
+       STAILQ_HEAD(keys_head, security_association_key) keys;
+       Boolean         seqnum_ind;    /* not supported in 1588-2019 */
+       UInteger16      seqnum_len;    /* value of “S” in Table 131 */
+       UInteger16      seqid_window;  /* sequenceID window for anti-replay */
+       Boolean         immediate_ind; /* immediate or delayed boolean */
+       Boolean         res_ind;       /* not supported in 1588-2019 */
+       UInteger16      res_len;       /* value of “R” in Table 131 */
+       Boolean         mutable;       /* allow for mutable correction */
+       UInteger16      last_seqid;
+};
+
+/**
+ * Read the defined security association file and append to config.
+ * @param cfg  config where security association database should be stored
+ * @return     -1 if the read failed, 0 otherwise
+ */
+int sad_create(struct config *cfg);
+
+/**
+ * Free current security association database
+ * @param cfg  config where security association database should is stored
+ */
+void sad_destroy(struct config *cfg);
+
+#endif
diff --git a/sad_private.h b/sad_private.h
new file mode 100644
index 0000000..141970c
--- /dev/null
+++ b/sad_private.h
@@ -0,0 +1,69 @@
+/**
+ * @file sad_private.h
+ * @brief Security Association Database
+ *
+ * This program 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.
+ *
+ * This program 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.
+ */
+#ifndef HAVE_SAD_PRIVATE_H
+#define HAVE_SAD_PRIVATE_H
+
+#include <sys/queue.h>
+
+#include "pdt.h"
+
+typedef enum {
+       INVALID = 0,
+       HMAC_SHA256_128,
+       HMAC_SHA256,
+       CMAC_AES128,
+       CMAC_AES256,
+} integrity_alg_type;
+
+struct integrity_alg_info {
+       const char         *label;
+       integrity_alg_type type; /* algorithm type - minimum HMAC-SHA256-128 */
+       UInteger16         len;  /* length of icv */
+};
+
+struct mac_data;
+struct security_association_key {
+       STAILQ_ENTRY(security_association_key) list;
+       struct integrity_alg_info icv;
+       struct mac_data *data;    /* data for mac function */
+       UInteger32 key_id;        /* symmetric key ID */
+};
+
+int sad_hash(struct mac_data *mac_data,
+            const void *data, int data_len,
+            unsigned char *mac, int mac_len)
+{
+       pr_debug("security configured but not supported");
+       return 0;
+}
+
+struct mac_data *sad_init_mac(integrity_alg_type algorithm,
+                             const unsigned char *key, int key_len)
+{
+       pr_debug("security configured but not supported");
+       return NULL;
+}
+
+void sad_deinit_mac(struct mac_data *mac_data)
+{
+       pr_debug("security configured but not supported");
+       return;
+}
+
+#endif
-- 
2.42.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to