diff --git a/config.c b/config.c index 68da0f24..edda4081 100644 --- a/config.c +++ b/config.c @@ -253,6 +253,7 @@ static struct config_enum bmca_enu[] = { struct config_item config_tab[] = { PORT_ITEM_UIN("active_key_id", 0, 0, UINT32_MAX), + PORT_ITEM_INT("allow_unauth", 0, 0, 2), PORT_ITEM_INT("allowedLostResponses", 3, 1, 255), PORT_ITEM_INT("announceReceiptTimeout", 3, 2, UINT8_MAX), PORT_ITEM_ENU("asCapable", AS_CAPABLE_AUTO, as_capable_enu), diff --git a/makefile b/makefile index 05228b4c..5e172234 100644 --- a/makefile +++ b/makefile @@ -74,12 +74,12 @@ ptp4l: $(OBJ) nsm: config.o $(FILTERS) hash.o interface.o msg.o nsm.o phc.o print.o \ rtnl.o sk.o $(TRANSP) tlv.o tsproc.o util.o version.o -pmc: config.o hash.o interface.o msg.o phc.o pmc.o pmc_common.o print.o sk.o \ - tlv.o $(TRANSP) util.o version.o +pmc: config.o hash.o interface.o msg.o phc.o pmc.o pmc_common.o print.o \ + $(SECURITY) sk.o tlv.o $(TRANSP) util.o version.o phc2sys: clockadj.o clockcheck.o config.o hash.o interface.o msg.o \ - phc.o phc2sys.o pmc_agent.o pmc_common.o print.o $(SERVOS) sk.o stats.o \ - sysoff.o tlv.o $(TRANSP) util.o version.o + phc.o phc2sys.o pmc_agent.o pmc_common.o print.o $(SECURITY) $(SERVOS) \ + sk.o stats.o sysoff.o tlv.o $(TRANSP) util.o version.o hwstamp_ctl: hwstamp_ctl.o version.o @@ -88,11 +88,11 @@ phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o print.o version.o timemaster: phc.o print.o rtnl.o sk.o timemaster.o util.o version.o ts2phc: config.o clockadj.o hash.o interface.o msg.o phc.o pmc_agent.o \ - pmc_common.o print.o $(SERVOS) sk.o $(TS2PHC) tlv.o transport.o raw.o \ - udp.o udp6.o uds.o util.o version.o + pmc_common.o print.o $(SECURITY) $(SERVOS) sk.o $(TS2PHC) tlv.o transport.o \ + raw.o udp.o udp6.o uds.o util.o version.o tz2alt: config.o hash.o interface.o lstab.o msg.o phc.o pmc_common.o print.o \ - sk.o tlv.o $(TRANSP) tz2alt.o util.o version.o + $(SECURITY) sk.o tlv.o $(TRANSP) tz2alt.o util.o version.o version.o: .version version.sh $(filter-out version.d,$(DEPEND)) diff --git a/phc2sys.8 b/phc2sys.8 index df0608a4..dd97a708 100644 --- a/phc2sys.8 +++ b/phc2sys.8 @@ -1,4 +1,4 @@ -.TH PHC2SYS 8 "February 2023" "linuxptp" +.TH PHC2SYS 8 "March 2024" "linuxptp" .SH NAME phc2sys \- synchronize two or more clocks @@ -270,6 +270,15 @@ sets the program options. This is the only used option. .SH FILE OPTIONS +.TP +.B active_key_id +Used in conjunction with \fBspp\fR and \fBsa_file\fR directives to +specify which key from the \fBspp\fR defined Security Association +should be used for outbound icv calculations. All Security Assocations +are read from the file specified by \fBsa_file\fR. Requires \fBspp\fR +and \fBsa_file\fR directives. Must be in the range of 1 to 2^32-1, +inclusive. The default is 0 (disabled). + .TP .B clock_servo The servo which is used to synchronize the local clock. Valid values @@ -357,6 +366,14 @@ Same as option The address of the UNIX domain socket to be used by the refclock_sock servo. The default is /var/run/refclock.ptp.sock. +.TP +.B sa_file +Specifies the location of the file containing Security Associations used +for immediate security processing of the Authentication TLV in support of +the optional security mechanism defined in ieee1588-2019 ch 14.16. See +\fBSECURITY ASSOCIATION OPTIONS\fR for more info on file contents. +The default is an empty string. (disabled). + .TP .B sanity_freq_limit The maximum allowed frequency offset between uncorrected clock and the @@ -380,6 +397,15 @@ Same as option .B \-S (see above). +.TP +.B spp +Specifies the security parameters pointer for the desired security association +to be used for authentication tlv support. If specified, the port owning the +spp will attempt to attach (outbound) and check (inbound) authentication tlvs +for all messages in accordance to the corresponding security association +sourced via the \fBsa_file\fR directive. Not compatible with one step ports. +Must be in the range of -1 to 255, inclusive. The default is -1 (disabled). + .TP .B transportSpecific The transport specific field. Must be in the range 0 to 255. diff --git a/phc2sys.c b/phc2sys.c index 726c67fc..61135394 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -49,6 +49,7 @@ #include "pi.h" #include "pmc_agent.h" #include "print.h" +#include "sad.h" #include "servo.h" #include "sk.h" #include "stats.h" @@ -1447,6 +1448,10 @@ int main(int argc, char *argv[]) n_domains = 1; } + if (sad_create(cfg)) { + goto end; + } + for (i = 0; i < n_domains; i++) { domains[i] = settings; domains[i].agent = pmc_agent_create(); diff --git a/pmc.8 b/pmc.8 index 629eadf2..2b08f4d2 100644 --- a/pmc.8 +++ b/pmc.8 @@ -1,4 +1,4 @@ -.TH PMC 8 "February 2023" "linuxptp" +.TH PMC 8 "March 2024" "linuxptp" .SH NAME pmc \- PTP management client @@ -144,8 +144,38 @@ options. The name of the section is the name of the configured port (e.g. .B domainNumber The domain attribute of the local clock. The default is 0. +.TP +.B sa_file +Specifies the location of the file containing Security Associations +used for immediate security processing of the Authentication TLV in +support of the optional security mechanism defined in ieee1588-2019 +ch 14.16. See \fBSECURITY ASSOCIATION OPTIONS\fR for information on how +this file should be formatted. \fBspp\fR and \fBactive_key_id\fR should +be specifed for each port to indicate which Security Association from +the /fBsa_file/fR should be used. The default is an empty string. + .SH PORT OPTIONS +.TP +.B active_key_id +Used in conjunction with \fBspp\fR and \fBsa_file\fR directives to +specify which key from the \fBspp\fR defined Security Association +should be used for outbound icv calculations. All Security Assocations +are read from the file specified by \fBsa_file\fR. Requires \fBspp\fR +and \fBsa_file\fR directives. Must be in the range of 1 to 2^32-1, +inclusive. The default is 0 (disabled). + +.TP +.B allow_unauth +Allows for pmc to accept unauthenticated management response and +signaling messages when authentication is enabled and \fBspp\fR, +\fBactive_key_id\fR and \fBsa_file\fR are set. Possible values are: + 0: normal receiving + 1: accept mgmt resp/signaling without Authentication TLV + 2: accept mgmt resp/signaling without Authentication TLV or with wrong + Authentication TLV +The default is 0 (disabled). + .TP .B network_transport Select the network transport. Possible values are UDPv4, UDPv6 and L2. The default @@ -155,6 +185,20 @@ is UDPv4. .B ptp_dst_mac The MAC address to which PTP management messages should be sent. Relevant only with L2 transport. The default is 01:1B:19:00:00:00. +.TP +.B spp +Specifies the Security Parameters Pointer of the desired Security +Association to be used for Authentication TLV support for a given port. +Any port with an assigned spp will attach Authentication TLVs to all +outbound messages and check for Authentication TLVs on all inbound +messages in accordance to the corresponding security association +sourced via the \fBsa_file\fR directive. Outbound Authentication TLVs +are generated using the key specified by \fBactive_key_id\fR. Not +compatible with one step ports or advertised versions less then +PTPv2.1. Requires \fBsa_file\fR and \fBactive_key_id\fR directives. +Must be in the range of 0 to 255, inclusive. +The default is -1 (disabled). + .TP .B transportSpecific The transport specific field. Must be in the range 0 to 255. diff --git a/pmc.c b/pmc.c index c50d46f4..0b61da4f 100644 --- a/pmc.c +++ b/pmc.c @@ -31,6 +31,7 @@ #include "notification.h" #include "pmc_common.h" #include "print.h" +#include "sad.h" #include "tlv.h" #include "uds.h" #include "util.h" @@ -712,7 +713,7 @@ int main(int argc, char *argv[]) int ret = 0; char line[1024], *command = NULL, uds_local[MAX_IFNAME_SIZE + 1]; enum transport_type transport_type = TRANS_UDP_IPV4; - UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0; + UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0, allow_unauth = 0; struct ptp_message *msg; struct option *opts; struct config *cfg; @@ -826,6 +827,11 @@ int main(int argc, char *argv[]) transport_type = config_get_int(cfg, NULL, "network_transport"); transport_specific = config_get_int(cfg, NULL, "transportSpecific") << 4; domain_number = config_get_int(cfg, NULL, "domainNumber"); + allow_unauth = config_get_int(cfg, NULL, "allow_unauth"); + + if (sad_create(cfg)) { + goto out; + } if (!iface_name) { if (transport_type == TRANS_UDS) { @@ -847,7 +853,7 @@ int main(int argc, char *argv[]) pmc = pmc_create(cfg, transport_type, iface_name, config_get_string(cfg, NULL, "uds_address"), boundary_hops, domain_number, transport_specific, - zero_datalen); + allow_unauth, zero_datalen); if (!pmc) { fprintf(stderr, "failed to create pmc\n"); config_destroy(cfg); @@ -928,6 +934,7 @@ int main(int argc, char *argv[]) msg_cleanup(); out: + sad_destroy(cfg); config_destroy(cfg); return ret; } diff --git a/pmc_agent.c b/pmc_agent.c index b6ed996a..86b6ee65 100644 --- a/pmc_agent.c +++ b/pmc_agent.c @@ -245,7 +245,7 @@ int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds, node->pmc = pmc_create(cfg, TRANS_UDS, uds, config_get_string(cfg, NULL, "uds_address"), 0, config_get_int(cfg, NULL, "domainNumber"), - config_get_int(cfg, NULL, "transportSpecific") << 4, 1); + config_get_int(cfg, NULL, "transportSpecific") << 4, 0, 1); if (!node->pmc) { pr_err("failed to create pmc"); return -1; diff --git a/pmc_common.c b/pmc_common.c index d71c7438..7c77a10f 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -25,6 +25,7 @@ #include "notification.h" #include "print.h" +#include "sad.h" #include "tlv.h" #include "transport.h" #include "pmc_common.h" @@ -481,6 +482,7 @@ static void print_help(FILE *fp) } struct pmc { + struct config *cfg; UInteger16 sequence_id; UInteger8 boundary_hops; UInteger8 domain_number; @@ -492,12 +494,16 @@ struct pmc { struct interface *iface; struct fdarray fdarray; int zero_length_gets; + int spp; + UInteger32 active_key_id; + UInteger8 allow_unauth; }; struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, const char *iface_name, const char *remote_address, UInteger8 boundary_hops, UInteger8 domain_number, - UInteger8 transport_specific, int zero_datalen) + UInteger8 transport_specific, UInteger8 allow_unauth, + int zero_datalen) { struct pmc *pmc; UInteger32 proc_id; @@ -524,6 +530,14 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, pmc->boundary_hops = boundary_hops; pmc->domain_number = domain_number; pmc->transport_specific = transport_specific; + pmc->cfg = cfg; + pmc->spp = config_get_int(cfg, NULL, "spp"); + pmc->active_key_id = config_get_uint(cfg, NULL, "active_key_id"); + pmc->allow_unauth = allow_unauth; + + if (sad_readiness_check(pmc->spp, pmc->active_key_id, pmc->cfg)) { + goto failed; + } pmc->transport = transport_create(cfg, transport_type); if (!pmc->transport) { @@ -595,7 +609,12 @@ static int pmc_send(struct pmc *pmc, struct ptp_message *msg) { int err; - err = msg_pre_send(msg); + if (pmc->spp >= 0) { + err = sad_append_auth_tlv(pmc->cfg, pmc->spp, + pmc->active_key_id, msg); + } else { + err = msg_pre_send(msg); + } if (err) { pr_err("msg_pre_send failed"); return -1; @@ -815,8 +834,9 @@ int pmc_send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name) struct ptp_message *pmc_recv(struct pmc *pmc) { - struct ptp_message *msg; - int cnt, err; + struct ptp_message *msg, *dup = NULL; + int cnt, err, spp = pmc->spp; + struct tlv_extra *extra; msg = msg_allocate(); if (!msg) { @@ -829,6 +849,12 @@ struct ptp_message *pmc_recv(struct pmc *pmc) pr_err("recv message failed"); goto failed; } + if (spp >= 0) { + dup = msg_duplicate(msg, 0); + if (!dup) { + goto failed; + } + } err = msg_post_recv(msg, cnt); if (err) { switch (err) { @@ -846,10 +872,40 @@ struct ptp_message *pmc_recv(struct pmc *pmc) msg_type_string(msg_type(msg))); goto failed; } - + if (pmc->allow_unauth && (msg_type(msg) == SIGNALING || + (msg_type(msg) == MANAGEMENT && management_action(msg) == RESPONSE))) { + spp = -1; + TAILQ_FOREACH(extra, &msg->tlv_list, list) { + if (extra->tlv->type == TLV_AUTHENTICATION) { + spp = pmc->spp; + } + } + } + err = sad_process_auth(pmc->cfg, spp, msg, dup); + if (err) { + if (pmc->allow_unauth == 2) { + pr_notice("auth failed but allow_unauth set"); + } else { + switch (err) { + case -EBADMSG: + pr_err("auth: bad message"); + break; + case -EPROTO: + pr_debug("auth: ignoring message"); + break; + } + goto failed; + } + } + if (dup) { + msg_put(dup); + } return msg; failed: msg_put(msg); + if (dup) { + msg_put(dup); + } return NULL; } diff --git a/pmc_common.h b/pmc_common.h index 355b2c0f..7b76061d 100644 --- a/pmc_common.h +++ b/pmc_common.h @@ -31,7 +31,8 @@ struct pmc; struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type, const char *iface_name, const char *remote_address, UInteger8 boundary_hops, UInteger8 domain_number, - UInteger8 transport_specific, int zero_datalen); + UInteger8 transport_specific, UInteger8 allow_unauth, + int zero_datalen); void pmc_destroy(struct pmc *pmc); diff --git a/port.c b/port.c index 754c9f0a..62c48df7 100644 --- a/port.c +++ b/port.c @@ -1956,7 +1956,7 @@ static int port_cmlds_initialize(struct port *p) hops, config_get_int(cfg, p->name, "cmlds.domainNumber"), config_get_int(cfg, p->name, "cmlds.majorSdoId") << 4, - zero_datalen); + 0, zero_datalen); if (!p->cmlds.pmc) { return -1; } diff --git a/ts2phc.8 b/ts2phc.8 index 852a527e..7d781c97 100644 --- a/ts2phc.8 +++ b/ts2phc.8 @@ -1,4 +1,4 @@ -.TH TS2PHC 8 "February 2023" "linuxptp" +.TH TS2PHC 8 "March 2024" "linuxptp" .SH NAME ts2phc - Synchronizes one or more PTP Hardware Clocks using external time stamps. @@ -117,6 +117,15 @@ command line option. .SH GLOBAL OPTIONS +.TP +.B active_key_id +Used in conjunction with \fBspp\fR and \fBsa_file\fR directives to +specify which key from the \fBspp\fR defined Security Association +should be used for outbound icv calculations. All Security Assocations +are read from the file specified by \fBsa_file\fR. Requires \fBspp\fR +and \fBsa_file\fR directives. Must be in the range of 1 to 2^32-1, +inclusive. The default is 0 (disabled). + .TP .B first_step_threshold The maximum offset, specified in seconds, that the servo will correct by @@ -161,6 +170,14 @@ with the log level of the message as a number. The default is an empty string (which cannot be set in the configuration file as the option requires an argument). +.TP +.B sa_file +Specifies the location of the file containing Security Associations used +for immediate security processing of the Authentication TLV in support of +the optional security mechanism defined in ieee1588-2019 ch 14.16. See +\fBSECURITY ASSOCIATION OPTIONS\fR for more info on file contents. +The default is an empty string. (disabled). + .TP .B step_threshold The maximum offset, specified in seconds, that the servo will correct @@ -168,6 +185,15 @@ by changing the clock frequency instead of stepping the clock. When set to 0.0, the servo will never step the clock except on start. The default is 0.0. +.TP +.B spp +Specifies the security parameters pointer for the desired security association +to be used for authentication tlv support. If specified, the port owning the +spp will attempt to attach (outbound) and check (inbound) authentication tlvs +for all messages in accordance to the corresponding security association +sourced via the \fBsa_file\fR directive. Not compatible with one step ports. +Must be in the range of -1 to 255, inclusive. The default is -1 (disabled). + .TP .B ts2phc.nmea_remote_host, ts2phc.nmea_remote_port Specifies the remote host providing ToD information when using the diff --git a/ts2phc.c b/ts2phc.c index cec205d8..ccbf7723 100644 --- a/ts2phc.c +++ b/ts2phc.c @@ -18,6 +18,7 @@ #include "interface.h" #include "phc.h" #include "print.h" +#include "sad.h" #include "ts2phc.h" #include "version.h" @@ -35,9 +36,10 @@ static void ts2phc_cleanup(struct ts2phc_private *priv) ts2phc_pps_sink_cleanup(priv); if (priv->src) ts2phc_pps_source_destroy(priv->src); - if (priv->cfg) + if (priv->cfg) { + sad_destroy(priv->cfg); config_destroy(priv->cfg); - + } if (priv->agent) pmc_agent_destroy(priv->agent); @@ -663,6 +665,12 @@ int main(int argc, char *argv[]) STAILQ_INIT(&priv.sinks); + if (sad_create(cfg)) { + fprintf(stderr, "failed to get security associations\n"); + ts2phc_cleanup(&priv); + return -1; + } + snprintf(uds_local, sizeof(uds_local), "/var/run/ts2phc.%d", getpid()); diff --git a/tz2alt.8 b/tz2alt.8 index 8cf790b3..cb33de25 100644 --- a/tz2alt.8 +++ b/tz2alt.8 @@ -1,4 +1,4 @@ -.TH TS2ALT 8 "February 2023" "linuxptp" +.TH TS2ALT 8 "March 2024" "linuxptp" .SH NAME tz2alt - Monitors daylight savings time changes and publishes them to PTP stack. @@ -72,6 +72,15 @@ starting with # are ignored. .SH GLOBAL OPTIONS +.TP +.B active_key_id +Used in conjunction with \fBspp\fR and \fBsa_file\fR directives to +specify which key from the \fBspp\fR defined Security Association +should be used for outbound icv calculations. All Security Assocations +are read from the file specified by \fBsa_file\fR. Requires \fBspp\fR +and \fBsa_file\fR directives. Must be in the range of 1 to 2^32-1, +inclusive. The default is 0 (disabled). + .TP .B domainNumber The domain attribute of the local clock. @@ -99,6 +108,23 @@ with the log level of the message as a number. The default is an empty string (which cannot be set in the configuration file as the option requires an argument). +.TP +.B sa_file +Specifies the location of the file containing Security Associations used +for immediate security processing of the Authentication TLV in support of +the optional security mechanism defined in ieee1588-2019 ch 14.16. See +\fBSECURITY ASSOCIATION OPTIONS\fR for more info on file contents. +The default is an empty string. (disabled). + +.TP +.B spp +Specifies the security parameters pointer for the desired security association +to be used for authentication tlv support. If specified, the port owning the +spp will attempt to attach (outbound) and check (inbound) authentication tlvs +for all messages in accordance to the corresponding security association +sourced via the \fBsa_file\fR directive. Not compatible with one step ports. +Must be in the range of -1 to 255, inclusive. The default is -1 (disabled). + .TP .B transportSpecific The transport specific field. Must be in the range 0 to 255. diff --git a/tz2alt.c b/tz2alt.c index 723b92ab..905aa0bb 100644 --- a/tz2alt.c +++ b/tz2alt.c @@ -15,6 +15,7 @@ #include "lstab.h" #include "pmc_common.h" #include "print.h" +#include "sad.h" #include "version.h" #include "tz.h" @@ -184,7 +185,7 @@ static int update_ptp_serivce(struct tzinfo *tz, struct tzinfo *next) pmc = pmc_create(cfg, TRANS_UDS, uds_local, config_get_string(cfg, NULL, "uds_address"), 0, config_get_int(cfg, NULL, "domainNumber"), - config_get_int(cfg, NULL, "transportSpecific") << 4, 1); + config_get_int(cfg, NULL, "transportSpecific") << 4, 0, 1); if (!pmc) { return -1; } @@ -376,6 +377,10 @@ int main(int argc, char *argv[]) goto out; } + if (sad_create(cfg)) { + goto out; + } + print_set_progname(progname); print_set_tag(config_get_string(cfg, NULL, "message_tag")); print_set_level(config_get_int(cfg, NULL, "logging_level")); @@ -383,6 +388,7 @@ int main(int argc, char *argv[]) err = do_tztool(timezone); out: + sad_destroy(cfg); config_destroy(cfg); return err; }