Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

178 lines
5.0 KiB

  1. /*-
  2. * Copyright 2021 John-Mark Gurney.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23. * SUCH DAMAGE.
  24. *
  25. */
  26. #include <comms.h>
  27. #include <strobe_rng_init.h>
  28. static const size_t MAC_LEN = 8;
  29. static const size_t CHALLENGE_LEN = 16;
  30. static const uint8_t domain[] = "com.funkthat.lora.irrigation.shared.v0.0.1";
  31. static int comms_pktbuf_equal(struct pktbuf a, struct pktbuf b);
  32. /* returns 1 if equal, 0 if not equal */
  33. static int
  34. comms_pktbuf_equal(struct pktbuf a, struct pktbuf b)
  35. {
  36. if (a.pktlen != b.pktlen)
  37. return 0;
  38. return memcmp(a.pkt, b.pkt, a.pktlen) == 0;
  39. }
  40. size_t
  41. _strobe_state_size()
  42. {
  43. return sizeof(strobe_s);
  44. }
  45. void
  46. comms_init(struct comms_state *cs, process_msgfunc_t pmf, struct pktbuf *shared)
  47. {
  48. *cs = (struct comms_state){
  49. .cs_comm_state = COMMS_WAIT_REQUEST,
  50. .cs_procmsg = pmf,
  51. };
  52. strobe_init(&cs->cs_start, domain, sizeof domain - 1);
  53. if (shared != NULL)
  54. strobe_key(&cs->cs_start, SYM_KEY, shared->pkt, shared->pktlen);
  55. /* copy starting state over to initial state */
  56. cs->cs_state = cs->cs_start;
  57. }
  58. #define CONFIRMED_STR_BASE "confirmed"
  59. #define CONFIRMED_STR ((const uint8_t *)CONFIRMED_STR_BASE)
  60. #define CONFIRMED_STR_LEN (sizeof(CONFIRMED_STR_BASE) - 1)
  61. /*
  62. * encrypted data to be processed is passed in via pbin.
  63. *
  64. * The pktbuf pointed to by pbout contains the buffer that a [encrypted]
  65. * response will be written to. The length needs to be updated, where 0
  66. * means no reply.
  67. */
  68. void
  69. comms_process(struct comms_state *cs, struct pktbuf pbin, struct pktbuf *pbout)
  70. {
  71. uint8_t buf[64] = {};
  72. struct pktbuf pbmsg, pbrep;
  73. ssize_t cnt, ret, msglen;
  74. /* if the current msg matches the previous */
  75. if (comms_pktbuf_equal(pbin, cs->cs_prevmsg)) {
  76. /* send the previous response */
  77. pbout->pktlen = cs->cs_prevmsgresp.pktlen;
  78. memcpy(pbout->pkt, cs->cs_prevmsgresp.pkt, pbout->pktlen);
  79. return;
  80. }
  81. strobe_attach_buffer(&cs->cs_state, pbin.pkt, pbin.pktlen);
  82. cnt = strobe_get(&cs->cs_state, APP_CIPHERTEXT, buf, pbin.pktlen -
  83. MAC_LEN);
  84. msglen = cnt;
  85. cnt = strobe_get(&cs->cs_state, MAC, pbin.pkt +
  86. (pbin.pktlen - MAC_LEN), MAC_LEN);
  87. /* XXX - cnt != MAC_LEN test case */
  88. /*
  89. * if we have arrived here, MAC has been verified, and buf now
  90. * contains the data to operate upon.
  91. */
  92. /* attach the buffer for output */
  93. strobe_attach_buffer(&cs->cs_state, pbout->pkt, pbout->pktlen);
  94. ret = 0;
  95. switch (cs->cs_comm_state) {
  96. case COMMS_WAIT_REQUEST:
  97. /* XXX - reqreset check */
  98. bare_strobe_randomize(buf, CHALLENGE_LEN);
  99. ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, buf,
  100. CHALLENGE_LEN);
  101. ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
  102. strobe_operate(&cs->cs_state, RATCHET, NULL, 32);
  103. cs->cs_comm_state = COMMS_WAIT_CONFIRM;
  104. break;
  105. case COMMS_WAIT_CONFIRM:
  106. /* XXX - confirm check */
  107. ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, CONFIRMED_STR,
  108. CONFIRMED_STR_LEN);
  109. ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
  110. cs->cs_comm_state = COMMS_PROCESS_MSGS;
  111. break;
  112. case COMMS_PROCESS_MSGS: {
  113. uint8_t repbuf[pbout->pktlen - MAC_LEN];
  114. memset(repbuf, '\x00', sizeof repbuf);
  115. pbmsg.pkt = buf;
  116. pbmsg.pktlen = msglen;
  117. pbrep.pkt = repbuf;
  118. pbrep.pktlen = sizeof repbuf;
  119. cs->cs_procmsg(pbmsg, &pbrep);
  120. ret = strobe_put(&cs->cs_state, APP_CIPHERTEXT, repbuf,
  121. pbrep.pktlen);
  122. ret += strobe_put(&cs->cs_state, MAC, NULL, MAC_LEN);
  123. break;
  124. }
  125. }
  126. /* set the output buffer length */
  127. pbout->pktlen = ret;
  128. if (ret != 0) {
  129. /* we accepted a new message store it */
  130. /* store the req */
  131. cs->cs_prevmsg.pkt = cs->cs_prevmsgbuf;
  132. cs->cs_prevmsg.pktlen = pbin.pktlen;
  133. memcpy(cs->cs_prevmsg.pkt, pbin.pkt, pbin.pktlen);
  134. /* store the response */
  135. cs->cs_prevmsgresp.pkt = cs->cs_prevmsgrespbuf;
  136. cs->cs_prevmsgresp.pktlen = pbout->pktlen;
  137. memcpy(cs->cs_prevmsgresp.pkt, pbout->pkt, pbout->pktlen);
  138. }
  139. }