sad_process_auth() contains any security processing required for a given
security association including the actual check of auth tlvs.

sad_check_auth_tlv() will go through all attached tlvs looking for auth
tlvs and processing according to their corresponding security associations

Signed-off-by: Clay Kaiser <clay.kai...@ibm.com>
---
 sad.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sad.h |  15 +++++++
 2 files changed, 156 insertions(+)

diff --git a/sad.c b/sad.c
index b6ee416..62c56d4 100644
--- a/sad.c
+++ b/sad.c
@@ -36,6 +36,147 @@ static struct integrity_alg_info supported_algorithms [] = {
        { NULL, 0, 0 },
 };
 
+static struct security_association *sad_get_association(struct config *cfg,
+                                                       int spp)
+{
+       struct security_association *sa;
+       STAILQ_FOREACH(sa, &cfg->security_association_database, list) {
+               if (sa->spp == spp) {
+                       return sa;
+               }
+       }
+
+       pr_debug("sa %u not present", spp);
+       return NULL;
+}
+
+static struct security_association_key *sad_get_key(struct 
security_association *sa,
+                                                   UInteger32 key_id)
+{
+       struct security_association_key *key;
+       STAILQ_FOREACH(key, &sa->keys, list) {
+               if (key->key_id == key_id) {
+                       return key;
+               }
+       }
+
+       pr_debug("sa %u: key %u not present", sa->spp, key_id);
+       return NULL;
+}
+
+static inline int sad_get_auth_tlv_len(struct security_association *sa,
+                                      int icv_len)
+{
+       return sizeof(struct authentication_tlv) + /* size of base tlv */
+              (sa->res_ind ? sa->res_len : 0) + /* size of res field */
+              (sa->seqnum_ind ? sa->seqnum_len : 0) + /* size of seqnum field 
*/
+              icv_len; /* size of icv (defined by key) */
+}
+
+static int sad_check_auth_tlv(struct security_association *sa,
+                             struct ptp_message *msg,
+                             struct ptp_message *raw)
+{
+       struct tlv_extra *extra;
+       struct authentication_tlv *auth;
+       struct security_association_key *key;
+       unsigned char digest_buf[MAX_DIGEST_LENGTH];
+       void *icv;
+       int data_len, icv_len, err = -EPROTO;
+       /* process any/all authentication tlvs now */
+       TAILQ_FOREACH(extra, &msg->tlv_list, list) {
+               if (extra->tlv->type != TLV_AUTHENTICATION) {
+                       continue;
+               }
+               auth = (struct authentication_tlv *) extra->tlv;
+               memset(digest_buf, 0, MAX_DIGEST_LENGTH);
+
+               /* verify spp matches expectations */
+               if (sa->spp != auth->spp) {
+                       pr_debug("sa %u: received auth tlv"
+                                " with unexpected spp %u",
+                                sa->spp, auth->spp);
+                       return -EBADMSG;
+               }
+
+               /* verify res and seqnum field indicators match expectations */
+               if ((sa->res_ind != (auth->secParamIndicator & 0x1)) ||
+                   (sa->seqnum_ind != (auth->secParamIndicator & 0x2))) {
+                       pr_debug("sa %u: received auth tlv"
+                                " with unexpected sec param %d",
+                                sa->spp, auth->secParamIndicator);
+                       return -EBADMSG;
+               }
+
+               /* retrieve key specified in keyID field */
+               key = sad_get_key(sa, auth->keyID);
+               if (key == NULL) {
+                       pr_debug("sa %u: received auth tlv"
+                                " with unexpected key %u",
+                                sa->spp, auth->keyID);
+                       return -EBADMSG;
+               }
+
+               /* verify TLV length matches expectation */
+               if (auth->length != sad_get_auth_tlv_len(sa, key->icv.len) - 4) 
{
+                       pr_debug("sa %u: received auth tlv"
+                                " with unexpected length",
+                                sa->spp);
+                       return -EBADMSG;
+               }
+
+               /* set correction to zero if mutable fields are allowed */
+               if (sa->mutable) {
+                       raw->header.correction = 0;
+               }
+
+               /* determine start address of icv and data length */
+               icv = (void *) auth + sad_get_auth_tlv_len(sa, 0);
+               data_len = (char *) icv - (char *) msg;
+
+               /* generate digest/icv */
+               icv_len = sad_hash(key->data, raw, data_len,
+                                  digest_buf, key->icv.len);
+
+               /* compare output to icv attached to message */
+               if (icv_len != key->icv.len) {
+                       pr_debug("sa %u: icv length failed",
+                                sa->spp);
+                       return -EBADMSG;
+               }
+               if (memcmp(&digest_buf, icv, key->icv.len) != 0) {
+                       pr_debug("sa %u: icv compare failed",
+                                sa->spp);
+                       return -EBADMSG;
+               }
+               err = 0;
+       }
+       return err;
+}
+
+int sad_process_auth(struct config *cfg, int spp,
+                    struct ptp_message *msg,
+                    struct ptp_message *raw)
+{
+       struct security_association* sa;
+       int err = 0;
+       /* immediately return if security is not configured */
+       if (spp < 0) {
+               return err;
+       }
+       /* retrieve sa specified by spp */
+       sa = sad_get_association(cfg, spp);
+       if (sa == NULL) {
+               return -EPROTO;
+       }
+       /* detect and process any auth tlvs  */
+       err = sad_check_auth_tlv(sa, msg, raw);
+       if (err) {
+               return err;
+       }
+       return err;
+}
+
 static void sad_destroy_association(struct security_association *sa)
 {
        struct security_association_key *key;
diff --git a/sad.h b/sad.h
index a6b647d..9540b4d 100644
--- a/sad.h
+++ b/sad.h
@@ -37,6 +37,21 @@ struct security_association {
        UInteger16      last_seqid;
 };
 
+/**
+ * authentication processing:
+ *  1. check seqid (on sync/followup)
+ *  2. check for matching ICV
+ * @param cfg  pointer to config that contains sad
+ * @param spp  security parameters pointer for desired sa
+ * @param msg  pointer to formatted message
+ * @param raw  pointer to duplicated raw message used for icv compare
+ * @return     -EBADMSG if message field expectations are not met
+ *             -EPROTO if failed authentication (seqid or icv fail)
+ */
+int sad_process_auth(struct config *cfg, int spp,
+                    struct ptp_message *msg,
+                    struct ptp_message *raw);
+
 /**
  * Read the defined security association file and append to config.
  * @param cfg  config where security association database should be stored
-- 
2.42.1



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

Reply via email to