|
- /*-
- * Copyright 2021 John-Mark Gurney.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- #include <comms.h>
- #include <strobe_rng_init.h>
-
- static const size_t MAC_LEN = 8;
- static const size_t CHALLENGE_LEN = 16;
- static const uint8_t domain[] = "com.funkthat.lora.irrigation.shared.v0.0.1";
-
- static int comms_pktbuf_equal(struct pktbuf a, struct pktbuf b);
-
- /* returns 1 if equal, 0 if not equal */
- static int
- comms_pktbuf_equal(struct pktbuf a, struct pktbuf b)
- {
-
- if (a.pktlen != b.pktlen)
- return 0;
-
- return memcmp(a.pkt, b.pkt, a.pktlen) == 0;
- }
-
- size_t
- _strobe_state_size()
- {
-
- return sizeof(strobe_s);
- }
-
- void
- comms_init(struct comms_state *cs, process_msgfunc_t pmf, struct pktbuf *shared)
- {
-
- *cs = (struct comms_state){
- .cs_comm_state = COMMS_WAIT_REQUEST,
- .cs_procmsg = pmf,
- };
-
- strobe_init(&cs->cs_start, domain, sizeof domain - 1);
-
- if (shared != NULL)
- strobe_key(&cs->cs_start, SYM_KEY, shared->pkt, shared->pktlen);
-
- /* copy starting state over to initial state */
- cs->cs_state = cs->cs_start;
- }
-
- #define CONFIRMED_STR_BASE "confirmed"
- #define CONFIRMED_STR ((const uint8_t *)CONFIRMED_STR_BASE)
- #define CONFIRMED_STR_LEN (sizeof(CONFIRMED_STR_BASE) - 1)
-
- /*
- * encrypted data to be processed is passed in via pbin.
- *
- * The pktbuf pointed to by pbout contains the buffer that a [encrypted]
- * response will be written to. The length needs to be updated, where 0
- * means no reply.
- */
- void
- comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout)
- {
- uint8_t buf[64] = {};
- struct pktbuf pbmsg, pbrep;
- ssize_t cnt, ret, msglen;
-
- /* if the current msg matches the previous */
- if (comms_pktbuf_equal(pbin, cs->cs_prevmsg)) {
- /* send the previous response */
- pbout->pktlen = cs->cs_prevmsgresp.pktlen;
- memcpy(pbout->pkt, cs->cs_prevmsgresp.pkt, pbout->pktlen);
- return;
- }
-
- strobe_attach_buffer(&cs->cs_state, pbin.pkt, pbin.pktlen);
-
- cnt = strobe_get(&cs->cs_state, APP_CIPHERTEXT, buf, pbin.pktlen -
- MAC_LEN);
- msglen = cnt;
-
- cnt = strobe_get(&cs->cs_state, MAC, pbin.pkt +
- (pbin.pktlen - MAC_LEN), MAC_LEN);
-
- /* XXX - cnt != MAC_LEN test case */
-
- /*
- * if we have arrived here, MAC has been verified, and buf now
- * contains the data to operate upon.
- */
-
- /* attach the buffer for output */
- strobe_attach_buffer(&cs->cs_state, pbout->pkt, pbout->pktlen);
-
- ret = 0;
- switch (cs->cs_comm_state) {
- case COMMS_WAIT_REQUEST:
- /* XXX - reqreset check */
-
- bare_strobe_randomize(buf, CHALLENGE_LEN);
- ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, buf,
- CHALLENGE_LEN);
- ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
-
- strobe_operate(&cs->cs_state, RATCHET, NULL, 32);
-
- cs->cs_comm_state = COMMS_WAIT_CONFIRM;
- break;
-
- case COMMS_WAIT_CONFIRM:
- /* XXX - confirm check */
- ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, CONFIRMED_STR,
- CONFIRMED_STR_LEN);
- ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
- cs->cs_comm_state = COMMS_PROCESS_MSGS;
- break;
-
- case COMMS_PROCESS_MSGS: {
- uint8_t repbuf[pbout->pktlen - MAC_LEN];
-
- memset(repbuf, '\x00', sizeof repbuf);
-
- pbmsg.pkt = buf;
- pbmsg.pktlen = msglen;
-
- pbrep.pkt = repbuf;
- pbrep.pktlen = sizeof repbuf;
-
- cs->cs_procmsg(pbmsg, &pbrep);
-
- ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, repbuf,
- pbrep.pktlen);
- ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
-
- break;
- }
- }
-
- /* set the output buffer length */
- pbout->pktlen = ret;
-
- if (ret != 0) {
- /* we accepted a new message store it */
-
- /* store the req */
- cs->cs_prevmsg.pkt = cs->cs_prevmsgbuf;
- cs->cs_prevmsg.pktlen = pbin.pktlen;
- memcpy(cs->cs_prevmsg.pkt, pbin.pkt, pbin.pktlen);
-
- /* store the response */
- cs->cs_prevmsgresp.pkt = cs->cs_prevmsgrespbuf;
- cs->cs_prevmsgresp.pktlen = pbout->pktlen;
- memcpy(cs->cs_prevmsgresp.pkt, pbout->pkt, pbout->pktlen);
- }
- }
|