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