The standard specifies that the header sequence id should be checked to confirm the message has not been replayed. It specifies a seqid check for each message that has it's own sequence id pool but this is most relevant for sync/followup messages for which slaves do not confirm seqid currently.
The standard also mentioned a seqid window, for this patch, the seqid window specifies how far the seqid can advance from the last know seqid before it is considered a replay attack from before a seqid rollover. This patch introduces sad_check_seqid() in sad.c to check the seqid and sad_set_last_seqid() which is updates the last seqid upon successful sync in port_synchronize() and reset upon state transition in port_e2e_transition() and port_p2p_transition. Signed-off-by: Clay Kaiser <clay.kai...@ibm.com> --- port.c | 8 ++++++++ sad.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sad.h | 9 ++++++++ 3 files changed, 82 insertions(+) diff --git a/port.c b/port.c index 82ef73f..d7e5ec0 100644 --- a/port.c +++ b/port.c @@ -1380,6 +1380,8 @@ static void port_synchronize(struct port *p, break; } + sad_set_last_seqid(clock_config(p->clock), p->spp, seqid); + last_state = clock_servo_state(p->clock); state = clock_synchronize(p->clock, t2, t1c); switch (state) { @@ -2658,6 +2660,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -2671,6 +2674,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ } port_set_sync_tx_tmo(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_PASSIVE: port_set_announce_tmo(p); @@ -2678,6 +2682,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) case PS_UNCALIBRATED: flush_last_sync(p); flush_delay_req(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); @@ -2702,6 +2707,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -2716,6 +2722,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ } port_set_sync_tx_tmo(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_PASSIVE: port_set_announce_tmo(p); @@ -2723,6 +2730,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) case PS_UNCALIBRATED: flush_last_sync(p); flush_peer_delay(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); diff --git a/sad.c b/sad.c index 62c56d4..5129675 100644 --- a/sad.c +++ b/sad.c @@ -73,6 +73,66 @@ static inline int sad_get_auth_tlv_len(struct security_association *sa, icv_len; /* size of icv (defined by key) */ } +void sad_set_last_seqid(struct config *cfg, + int spp, UInteger16 seqid) +{ + struct security_association* sa; + /* immediately return if security is not configured */ + if (spp < 0) { + return; + } + /* retrieve sa specified by spp */ + sa = sad_get_association(cfg, spp); + if (sa == NULL) { + return; + } + + sa->last_seqid = seqid; +} + +static int sad_check_seqid(struct ptp_message *msg, + UInteger16 last_seqid, + UInteger16 seqid_window) +{ + UInteger16 new_seqid; + /* do not check seqid if seqid_window is zero */ + if (seqid_window < 1) { + return 0; + } + + /* (for now) only check seqid on sync/followup msgs */ + switch (msg_type(msg)) { + case SYNC: + case FOLLOW_UP: + new_seqid = msg->header.sequenceId; + /* verify received seqid is greater than last */ + /* use mod(uint16) to handle wrap within window */ + if (new_seqid < (UInteger16)(last_seqid + 1) && + (UInteger16)(new_seqid + seqid_window) < + (UInteger16)(last_seqid + 1 + seqid_window) && + last_seqid != 0) { + pr_debug("replayed seqid: received seqid %u " + "smaller than last %u", + new_seqid, last_seqid); + return -EBADMSG; + /* verify received seqid is less than seqid window */ + /* use mod(uint16) to handle wrap within window */ + } else if (new_seqid > (UInteger16)(last_seqid + seqid_window) && + (UInteger16)(new_seqid + seqid_window) > + (UInteger16)(last_seqid + 2 * seqid_window) && + last_seqid != 0) { + pr_debug("replayed seqid: received seqid %u " + "beyond seqid_window %u + %d", + new_seqid, last_seqid, seqid_window); + return -EBADMSG; + } + break; + default: + break; + } + return 0; +} + static int sad_check_auth_tlv(struct security_association *sa, struct ptp_message *msg, struct ptp_message *raw) @@ -169,6 +229,11 @@ int sad_process_auth(struct config *cfg, int spp, if (sa == NULL) { return -EPROTO; } + /* check seqid in header first (sync/followup only) */ + err = sad_check_seqid(msg, sa->last_seqid, sa->seqid_window); + if (err) { + return err; + } /* detect and process any auth tlvs */ err = sad_check_auth_tlv(sa, msg, raw); if (err) { diff --git a/sad.h b/sad.h index 9540b4d..4ab4ea2 100644 --- a/sad.h +++ b/sad.h @@ -37,6 +37,15 @@ struct security_association { UInteger16 last_seqid; }; +/** + * Check the sequence id on header + * @param cfg pointer to config that contains sad + * @param spp security parameters pointer for desired sa + * @param seqid sequence id to store in SA +*/ +void sad_set_last_seqid(struct config *cfg, int spp, + UInteger16 seqid); + /** * authentication processing: * 1. check seqid (on sync/followup) -- 2.42.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel