You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2026/10/10 13:01:28 UTC
(nuttx) 04/05: arch/mips/pic32mz: add WPA3-Personal for the PIC32MZ-W1 Wi-Fi.
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 3edc27ba26235a9c174bf150806c380232fabe62
Author: Daniel P. Carvalho <da...@gmail.com>
AuthorDate: Fri Oct 9 09:29:54 2026 -0300
arch/mips/pic32mz: add WPA3-Personal for the PIC32MZ-W1 Wi-Fi.
Add a driver for the PIC32MZ-W1 BA414E public key engine (modular add,
subtract, multiply and exponentiation; P-256 point add, double, multiply
and on-curve check) and use it for the big number and elliptic curve
services the WLAN library calls for WPA3-Personal (SAE), as a station
and as a Soft-AP. When the library passes a completion callback, the
operation completes at once and the callback is queued and run from the
WLAN thread, as the library expects. wapi selects WPA3 with WPA version
3 (IW_AUTH_WPA_VERSION_WPA3).
The engine runs a microcode program that is under Microchip's license
and not part of NuttX. By default the build downloads
drivers/ba414e/src/drv_ba414e.c from the MPLAB Harmony crypto repository
(v3.9.0) and generates a C file with the microcode; alternatively the
microcode is read from a file on first use (the format is documented in
the Kconfig help and in pic32mz_ba414e.c). An optional self-test runs
known-answer tests when the microcode is loaded.
Register addresses come from the PIC32MZ-W_DFP [DFP]; the programming
model and the library interface facts come from Microchip's Harmony
sources and are tagged [EX]; no code was copied.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Daniel P. Carvalho <da...@gmail.com>
---
arch/mips/src/pic32mz/.gitignore | 2 +
arch/mips/src/pic32mz/Kconfig | 58 +-
arch/mips/src/pic32mz/Make.defs | 38 +-
arch/mips/src/pic32mz/pic32mz_ba414e.c | 943 +++++++++++++++++++++++++
arch/mips/src/pic32mz/pic32mz_ba414e.h | 111 +++
arch/mips/src/pic32mz/pic32mz_w1_wlan.c | 112 +++
arch/mips/src/pic32mz/pic32mz_w1_wlan.h | 9 +
arch/mips/src/pic32mz/pic32mz_w1_wlan_crypto.c | 371 +++++++++-
8 files changed, 1637 insertions(+), 7 deletions(-)
diff --git a/arch/mips/src/pic32mz/.gitignore b/arch/mips/src/pic32mz/.gitignore
index 765a3271c66..a99e7e769d8 100644
--- a/arch/mips/src/pic32mz/.gitignore
+++ b/arch/mips/src/pic32mz/.gitignore
@@ -1,2 +1,4 @@
/pic32mzw1.a
/libpic32mzw1_nx.a
+/drv_ba414e.c
+/pic32mz_ba414e_ucode.c
diff --git a/arch/mips/src/pic32mz/Kconfig b/arch/mips/src/pic32mz/Kconfig
index 2d540fdbf99..d32fe474f1d 100644
--- a/arch/mips/src/pic32mz/Kconfig
+++ b/arch/mips/src/pic32mz/Kconfig
@@ -153,9 +153,9 @@ config PIC32MZ_W1_WLAN
Wi-Fi network device (wlan0) built on Microchip's closed PIC32MZ-W1
WLAN library (pic32mzw1.a from the MPLAB Harmony wireless_wifi
repository, downloaded at build time under Microchip's license).
- Station or Soft-AP, open or WPA/WPA2-Personal, configured through
- wapi. The library is built with XC32 (microMIPS, soft-float), so
- only XC32 is supported.
+ Station or Soft-AP, open or WPA/WPA2-Personal (WPA3-Personal with
+ PIC32MZ_W1_BA414E), configured through wapi. The library is built
+ with XC32 (microMIPS, soft-float), so only XC32 is supported.
if PIC32MZ_W1_WLAN
@@ -167,6 +167,58 @@ config PIC32MZ_W1_WLAN_STACKSIZE
int "WLAN thread stack size"
default 4096
+config PIC32MZ_W1_BA414E
+ bool "BA414E public key engine (WPA3-Personal)"
+ default n
+ ---help---
+ Use the BA414E public key engine for the big number and elliptic
+ curve operations of WPA3-Personal (SAE), station and Soft-AP.
+ Without it only open and WPA/WPA2-Personal networks are
+ supported. The engine runs a microcode program from Microchip's
+ MPLAB Harmony driver source (drivers/ba414e/src/drv_ba414e.c in
+ https://github.com/Microchip-MPLAB-Harmony/crypto), which is
+ under Microchip's license and not part of NuttX.
+
+if PIC32MZ_W1_BA414E
+
+choice
+ prompt "BA414E microcode"
+ default PIC32MZ_W1_BA414E_UCODE_BUILTIN
+
+config PIC32MZ_W1_BA414E_UCODE_BUILTIN
+ bool "Download at build time"
+ ---help---
+ Download drv_ba414e.c (Harmony crypto v3.9.0) at build time and
+ link its microcode into the image.
+
+config PIC32MZ_W1_BA414E_UCODE_FILE
+ bool "Load from a file"
+ ---help---
+ Load the microcode from a file when the engine is first used,
+ that is on the first WPA3 connection or Soft-AP start. The file
+ holds the 810 32-bit values of the init_ucode_array[810]
+ initializer of drv_ba414e.c, in array order, each little endian:
+ no header, exactly 3240 bytes. Any file system works (ROMFS,
+ tmpfs, a flash file system...) as long as the file is there
+ before the first use.
+
+endchoice
+
+config PIC32MZ_W1_BA414E_UCODE_PATH
+ string "Microcode file"
+ default "/etc/ba414e.bin"
+ depends on PIC32MZ_W1_BA414E_UCODE_FILE
+
+config PIC32MZ_W1_BA414E_SELFTEST
+ bool "BA414E self-test"
+ default n
+ ---help---
+ Run known-answer tests of the BA414E primitives (P-256 and
+ modular arithmetic) once the microcode is loaded, and log the
+ results and times.
+
+endif # PIC32MZ_W1_BA414E
+
endif # PIC32MZ_W1_WLAN
menu "PIC32MZ Peripheral Support"
diff --git a/arch/mips/src/pic32mz/Make.defs b/arch/mips/src/pic32mz/Make.defs
index 031a37cc3bb..b0defb27e78 100644
--- a/arch/mips/src/pic32mz/Make.defs
+++ b/arch/mips/src/pic32mz/Make.defs
@@ -106,11 +106,47 @@ LDFLAGS += --defsym=NVMADDR=0xbf800630 --defsym=NVMDATA0=0xbf800640
LDFLAGS += --defsym=NVMSRCADDR=0xbf8006c0 --defsym=NVMLBWP=0xbf8006f0
endif
-# Delete the downloaded library and its copy whatever the configuration
+ifeq ($(CONFIG_PIC32MZ_W1_BA414E),y)
+CHIP_CSRCS += pic32mz_ba414e.c
+endif
+
+ifeq ($(CONFIG_PIC32MZ_W1_BA414E_UCODE_BUILTIN),y)
+CHIP_CSRCS += pic32mz_ba414e_ucode.c
+
+# The BA414E microcode is not part of NuttX either: download Microchip's
+# driver source from the MPLAB Harmony crypto repository and generate a C
+# file with its init_ucode_array values (810 32-bit words).
+
+BA414E_VER = v3.9.0
+BA414E_URL = https://github.com/Microchip-MPLAB-Harmony/crypto/raw/$(BA414E_VER)/drivers/ba414e/src
+BA414E_SRC = chip$(DELIM)drv_ba414e.c
+BA414E_UCODE = chip$(DELIM)pic32mz_ba414e_ucode.c
+
+$(BA414E_SRC):
+ $(call DOWNLOAD,$(BA414E_URL),drv_ba414e.c,$(BA414E_SRC))
+
+$(BA414E_UCODE): $(BA414E_SRC)
+ $(Q) n=`sed -n '/init_ucode_array\[810\]/,/};/p' $< | grep -o 0x | wc -l`; \
+ if [ $$n -ne 810 ]; then \
+ echo "ERROR: no BA414E microcode in $<"; rm -f $<; exit 1; \
+ fi
+ $(Q) { echo "/* Generated from Microchip's drv_ba414e.c $(BA414E_VER) */"; \
+ echo "#include <stdint.h>"; \
+ echo "const uint32_t g_ba414e_ucode[810] ="; \
+ echo "{"; \
+ sed -n '/init_ucode_array\[810\]/,/};/p' $< | sed '1d;$$d'; \
+ echo "};"; } > $@
+
+context:: $(BA414E_UCODE)
+endif
+
+# Delete the downloaded and generated files whatever the configuration
distclean::
$(call DELFILE, chip$(DELIM)pic32mzw1.a)
$(call DELFILE, chip$(DELIM)libpic32mzw1_nx.a)
+ $(call DELFILE, chip$(DELIM)drv_ba414e.c)
+ $(call DELFILE, chip$(DELIM)pic32mz_ba414e_ucode.c)
ifeq ($(CONFIG_PIC32MZ_GPIOIRQ),y)
CHIP_CSRCS += pic32mz_gpioirq.c
diff --git a/arch/mips/src/pic32mz/pic32mz_ba414e.c b/arch/mips/src/pic32mz/pic32mz_ba414e.c
new file mode 100644
index 00000000000..d25200a5e69
--- /dev/null
+++ b/arch/mips/src/pic32mz/pic32mz_ba414e.c
@@ -0,0 +1,943 @@
+/****************************************************************************
+ * arch/mips/src/pic32mz/pic32mz_ba414e.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/* PIC32MZ-W1 asymmetric crypto engine (BA414E): modular arithmetic and
+ * elliptic curve primitives. DS70005425 (chapter 26) documents only the
+ * memories; the programming model below comes from Microchip's MPLAB
+ * Harmony driver (crypto/drivers/ba414e) and is marked [EX]. Register
+ * addresses and fields are from the PIC32MZ-W_DFP [DFP].
+ *
+ * The engine runs a microcode program that must be loaded before the
+ * first operation. It is under Microchip's license and not part of
+ * NuttX: either the build downloads Microchip's driver source and links
+ * the microcode into the image (CONFIG_PIC32MZ_W1_BA414E_UCODE_BUILTIN),
+ * or it is read from a file on first use
+ * (CONFIG_PIC32MZ_W1_BA414E_UCODE_FILE).
+ *
+ * Microcode file format: the 810 32-bit values of the init_ucode_array[810]
+ * initializer in drivers/ba414e/src/drv_ba414e.c of
+ * https://github.com/Microchip-MPLAB-Harmony/crypto, in array order, each
+ * stored little endian; no header, exactly 3240 bytes. For example, the
+ * first values 0x10032004, 0x48013e00 give the bytes
+ * 04 20 03 10 00 3e 01 48.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <syslog.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/irq.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+
+#include <arch/irq.h>
+
+#include "mips_internal.h"
+#include <arch/board/board.h>
+
+#include "hardware/pic32mzw1_features.h"
+#include "pic32mz_ba414e.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* [DFP] Registers */
+
+#define BA414E_PKCONFIG 0xbf920000
+#define BA414E_PKCOMMAND 0xbf920004
+#define BA414E_PKCONTROL 0xbf920008
+#define BA414E_PKSTATUS 0xbf92000c
+
+/* [DFP] PKCONFIG: operand slot pointers */
+
+#define PKCONFIG_OPPTRA(n) ((uint32_t)(n) << 0)
+#define PKCONFIG_OPPTRB(n) ((uint32_t)(n) << 8)
+#define PKCONFIG_OPPTRC(n) ((uint32_t)(n) << 16)
+
+/* [DFP] PKCOMMAND fields */
+
+#define PKCOMMAND_OPERATION(n) ((uint32_t)(n) << 0)
+#define PKCOMMAND_OPSIZE(n) ((uint32_t)(n) << 8)
+#define PKCOMMAND_CALCR2 (1u << 31)
+
+/* [DFP] PKCONTROL.START */
+
+#define PKCONTROL_START (1u << 0)
+
+/* [DFP] PKSTATUS fields */
+
+#define PKSTATUS_PXNOC (1u << 4) /* Point not on curve */
+#define PKSTATUS_PXINF (1u << 5) /* Point at infinity */
+
+/* [DFP] Shared crypto memory (operand slots) and microcode memory (KSEG1) */
+
+#define BA414E_SCM_BASE 0xbf900000
+#define BA414E_UCM_BASE 0xbf902000
+
+/* [EX] Shared memory size, 64-byte operand slots */
+
+#define BA414E_SCM_SIZE 2432
+#define BA414E_SLOT_SIZE 64
+#define BA414E_SLOT(n) (BA414E_SCM_BASE + (n) * BA414E_SLOT_SIZE)
+
+/* [EX] Microcode: 90 groups of nine 32-bit words, each packing sixteen
+ * 18-bit microcode words, most significant bits first.
+ */
+
+#define BA414E_UCODE_GROUPS 90
+#define BA414E_UCODE_WORDS (BA414E_UCODE_GROUPS * 9)
+
+/* [DFP] PMD1.BA414MD: module disable */
+
+#define PMD1_BA414MD (1u << 23)
+
+/* [EX] Operation codes */
+
+#define OPC_MOD_ADD 0x01
+#define OPC_MOD_SUB 0x02
+#define OPC_MOD_MULT 0x03
+#define OPC_MOD_EXP 0x10
+#define OPC_ECC_DOUBLE 0x20
+#define OPC_ECC_ADD 0x21
+#define OPC_ECC_MULT 0x22
+#define OPC_ECC_ONCURVE 0x26
+
+/* [EX] Slots of the modular primitives (P, A, B -> C) */
+
+#define MOD_SLOT_P 0
+#define MOD_SLOT_A 1
+#define MOD_SLOT_B 2
+#define MOD_SLOT_C 3
+
+/* [EX] Slots of the modular exponentiation (C = M^e mod n) */
+
+#define EXP_SLOT_N 0
+#define EXP_SLOT_E 1
+#define EXP_SLOT_M 2
+#define EXP_SLOT_C 3
+
+/* [EX] Slots of the ECC primitives */
+
+#define ECC_SLOT_P 0
+#define ECC_SLOT_N 1
+#define ECC_SLOT_GX 2
+#define ECC_SLOT_GY 3
+#define ECC_SLOT_A 4
+#define ECC_SLOT_B 5
+#define ECC_SLOT_P1X 6
+#define ECC_SLOT_P1Y 7
+#define ECC_SLOT_P2X 8
+#define ECC_SLOT_P2Y 9
+#define ECC_SLOT_P3X 10
+#define ECC_SLOT_P3Y 11
+#define ECC_SLOT_K 12
+
+#define BA414E_TIMEOUT SEC2TICK(1)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const uint8_t g_p256_p[32] =
+{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static const uint8_t g_p256_n[32] =
+{
+ 0x51, 0x25, 0x63, 0xfc, 0xc2, 0xca, 0xb9, 0xf3,
+ 0x84, 0x9e, 0x17, 0xa7, 0xad, 0xfa, 0xe6, 0xbc,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static const uint8_t g_p256_gx[32] =
+{
+ 0x96, 0xc2, 0x98, 0xd8, 0x45, 0x39, 0xa1, 0xf4,
+ 0xa0, 0x33, 0xeb, 0x2d, 0x81, 0x7d, 0x03, 0x77,
+ 0xf2, 0x40, 0xa4, 0x63, 0xe5, 0xe6, 0xbc, 0xf8,
+ 0x47, 0x42, 0x2c, 0xe1, 0xf2, 0xd1, 0x17, 0x6b
+};
+
+static const uint8_t g_p256_gy[32] =
+{
+ 0xf5, 0x51, 0xbf, 0x37, 0x68, 0x40, 0xb6, 0xcb,
+ 0xce, 0x5e, 0x31, 0x6b, 0x57, 0x33, 0xce, 0x2b,
+ 0x16, 0x9e, 0x0f, 0x7c, 0x4a, 0xeb, 0xe7, 0x8e,
+ 0x9b, 0x7f, 0x1a, 0xfe, 0xe2, 0x42, 0xe3, 0x4f
+};
+
+static const uint8_t g_p256_a[32] =
+{
+ 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static const uint8_t g_p256_b[32] =
+{
+ 0x4b, 0x60, 0xd2, 0x27, 0x3e, 0x3c, 0xce, 0x3b,
+ 0xf6, 0xb0, 0x53, 0xcc, 0xb0, 0x06, 0x1d, 0x65,
+ 0xbc, 0x86, 0x98, 0x76, 0x55, 0xbd, 0xeb, 0xb3,
+ 0xe7, 0x93, 0x3a, 0xaa, 0xd8, 0x35, 0xc6, 0x5a
+};
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_SELFTEST
+/* Self-test vectors (P-256, little endian): 2G, kG for
+ * k = 0xdeadbeef12345678, x of 4G, and 3^(p-2) mod p (the inverse of 3).
+ */
+
+static const uint8_t g_st_2gx[32] =
+{
+ 0x78, 0x99, 0x66, 0x47, 0xfc, 0x48, 0x0b, 0xa6,
+ 0x35, 0x1b, 0xf2, 0x77, 0xe2, 0x69, 0x89, 0xc0,
+ 0xc3, 0x1a, 0xb5, 0x04, 0x03, 0x38, 0x52, 0x8a,
+ 0x7e, 0x4f, 0x03, 0x8d, 0x18, 0x7b, 0xf2, 0x7c
+};
+
+static const uint8_t g_st_2gy[32] =
+{
+ 0xd1, 0x73, 0x78, 0x22, 0x9d, 0xb7, 0x04, 0x9e,
+ 0x29, 0x82, 0xe9, 0x3c, 0xe6, 0xad, 0x7d, 0xba,
+ 0xdb, 0x30, 0x74, 0x9f, 0xc6, 0x9a, 0x3d, 0x29,
+ 0x40, 0xd0, 0x8e, 0xdb, 0x10, 0x55, 0x77, 0x07
+};
+
+static const uint8_t g_st_kgx[32] =
+{
+ 0x60, 0x70, 0xe3, 0x37, 0x8c, 0x9a, 0xbd, 0xfd,
+ 0x9f, 0xfc, 0x20, 0xe4, 0xae, 0x29, 0x00, 0x8d,
+ 0x2f, 0xf1, 0x51, 0xb2, 0xdb, 0x1e, 0x9f, 0x17,
+ 0x13, 0x68, 0xf1, 0x7c, 0x4b, 0xc2, 0x9d, 0xfc
+};
+
+static const uint8_t g_st_kgy[32] =
+{
+ 0xbf, 0x2a, 0x5c, 0xe1, 0x3e, 0x15, 0xbb, 0x9f,
+ 0x23, 0x35, 0xae, 0xed, 0xb7, 0xf7, 0xcc, 0x55,
+ 0x98, 0xde, 0x03, 0x33, 0x39, 0x7b, 0xd8, 0xdc,
+ 0x4c, 0xbc, 0xc2, 0x52, 0x4c, 0x4d, 0xbc, 0x62
+};
+
+static const uint8_t g_st_4gx[32] =
+{
+ 0x52, 0x08, 0x03, 0x6b, 0x44, 0x02, 0x93, 0x50,
+ 0xef, 0x96, 0x55, 0x78, 0xdb, 0xe2, 0x1f, 0x03,
+ 0xd0, 0x2b, 0xe6, 0x9e, 0x65, 0xde, 0x2d, 0xa0,
+ 0xbb, 0x8f, 0xd0, 0x32, 0x35, 0x4a, 0x53, 0xe2
+};
+
+static const uint8_t g_st_inv3[32] =
+{
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0xab, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa
+};
+
+#endif
+
+static rmutex_t g_ba414e_lock = NXRMUTEX_INITIALIZER;
+static bool g_ba414e_loaded;
+static sem_t g_ba414e_done = SEM_INITIALIZER(0);
+static volatile uint32_t g_ba414e_status;
+static volatile bool g_ba414e_fault;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const struct ba414e_curve_s g_ba414e_p256 =
+{
+ 32, g_p256_p, g_p256_n, g_p256_gx, g_p256_gy, g_p256_a, g_p256_b
+};
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_UCODE_BUILTIN
+/* Microcode, generated at build time (see Make.defs) */
+
+extern const uint32_t g_ba414e_ucode[BA414E_UCODE_WORDS];
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* [EX] Operand size code: number of 64-bit words, 2 (128 bits) to 8 */
+
+static int ba414e_opsize(int len)
+{
+ int size = (len + 7) / 8;
+
+ return size < 2 ? 2 : size;
+}
+
+static void ba414e_write_slot(int slot, FAR const uint8_t *data, int len,
+ int slotlen)
+{
+ volatile uint32_t *dst = (volatile uint32_t *)BA414E_SLOT(slot);
+ uint32_t word;
+ int i;
+
+ /* Little endian, zero padded to the operand size; 32-bit accesses */
+
+ for (i = 0; i < slotlen; i += 4)
+ {
+ word = 0;
+ if (i < len)
+ {
+ word = data[i];
+ }
+
+ if (i + 1 < len)
+ {
+ word |= (uint32_t)data[i + 1] << 8;
+ }
+
+ if (i + 2 < len)
+ {
+ word |= (uint32_t)data[i + 2] << 16;
+ }
+
+ if (i + 3 < len)
+ {
+ word |= (uint32_t)data[i + 3] << 24;
+ }
+
+ *dst++ = word;
+ }
+}
+
+static void ba414e_read_slot(int slot, FAR uint8_t *data, int len)
+{
+ volatile uint32_t *src = (volatile uint32_t *)BA414E_SLOT(slot);
+ uint32_t word = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ if ((i & 3) == 0)
+ {
+ word = *src++;
+ }
+
+ data[i] = word & 0xff;
+ word >>= 8;
+ }
+}
+
+static void ba414e_clear_scm(void)
+{
+ volatile uint32_t *p = (volatile uint32_t *)BA414E_SCM_BASE;
+ int i;
+
+ for (i = 0; i < BA414E_SCM_SIZE / 4; i++)
+ {
+ p[i] = 0;
+ }
+}
+
+static void ba414e_load_ucode(FAR const uint32_t *in)
+{
+ volatile uint32_t *ucm = (volatile uint32_t *)BA414E_UCM_BASE;
+ uint64_t acc;
+ int bits;
+ int g;
+ int i;
+
+ for (g = 0; g < BA414E_UCODE_GROUPS; g++)
+ {
+ acc = 0;
+ bits = 0;
+
+ for (i = 0; i < 9; i++)
+ {
+ /* Shift in 32 bits, emit every complete 18-bit word */
+
+ acc = (acc << 32) | *in++;
+ bits += 32;
+
+ while (bits >= 18)
+ {
+ bits -= 18;
+ *ucm++ = (uint32_t)(acc >> bits) & 0x3ffff;
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_UCODE_FILE
+/* Read the microcode file (format in the header of this file) */
+
+static FAR uint32_t *ba414e_read_ucode(void)
+{
+ FAR const char *path = CONFIG_PIC32MZ_W1_BA414E_UCODE_PATH;
+ size_t size = BA414E_UCODE_WORDS * sizeof(uint32_t);
+ FAR uint32_t *ucode;
+ struct file file;
+ ssize_t nread;
+ size_t total = 0;
+ char extra;
+ int ret;
+ static bool warned;
+
+ ret = file_open(&file, path, O_RDONLY | O_CLOEXEC);
+ if (ret < 0)
+ {
+ /* Callers retry; report the missing file once */
+
+ if (!warned)
+ {
+ syslog(LOG_ERR, "ba414e: cannot open %s: %d\n", path, ret);
+ warned = true;
+ }
+
+ return NULL;
+ }
+
+ ucode = kmm_malloc(size);
+ if (ucode != NULL)
+ {
+ while (total < size)
+ {
+ nread = file_read(&file, (FAR uint8_t *)ucode + total,
+ size - total);
+ if (nread <= 0)
+ {
+ break;
+ }
+
+ total += nread;
+ }
+
+ /* The size must match exactly */
+
+ if (total != size || file_read(&file, &extra, 1) != 0)
+ {
+ syslog(LOG_ERR, "ba414e: %s is not %zu bytes\n", path, size);
+ kmm_free(ucode);
+ ucode = NULL;
+ }
+ }
+
+ file_close(&file);
+ return ucode;
+}
+#endif
+
+static int ba414e_isr(int irq, FAR void *context, FAR void *arg)
+{
+ /* [EX] Latch the status, stop the engine, mask the interrupt */
+
+ g_ba414e_status = getreg32(BA414E_PKSTATUS);
+ g_ba414e_fault = (irq == PIC32MZ_IRQ_CRYPTO1F);
+ putreg32(0, BA414E_PKCONTROL);
+
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1);
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1F);
+ mips_clrpend_irq(irq);
+
+ nxsem_post(&g_ba414e_done);
+ return OK;
+}
+
+/* Program the operation; the operands are written afterwards, since the
+ * slot size follows from the operand size.
+ */
+
+static void ba414e_setup(int opcode, int opsize, uint32_t config)
+{
+ putreg32(0, BA414E_PKCONTROL);
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1);
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1F);
+ mips_clrpend_irq(PIC32MZ_IRQ_CRYPTO1);
+ mips_clrpend_irq(PIC32MZ_IRQ_CRYPTO1F);
+
+ ba414e_clear_scm();
+
+ putreg32(config, BA414E_PKCONFIG);
+ putreg32(PKCOMMAND_OPERATION(opcode) | PKCOMMAND_OPSIZE(opsize) |
+ PKCOMMAND_CALCR2, BA414E_PKCOMMAND);
+}
+
+static int ba414e_run(void)
+{
+ int ret;
+
+ /* Drain a stale completion */
+
+ while (nxsem_trywait(&g_ba414e_done) == OK);
+
+ g_ba414e_fault = false;
+ up_enable_irq(PIC32MZ_IRQ_CRYPTO1F);
+ up_enable_irq(PIC32MZ_IRQ_CRYPTO1);
+ putreg32(PKCONTROL_START, BA414E_PKCONTROL);
+
+ ret = nxsem_tickwait_uninterruptible(&g_ba414e_done, BA414E_TIMEOUT);
+ if (ret < 0)
+ {
+ putreg32(0, BA414E_PKCONTROL);
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1);
+ up_disable_irq(PIC32MZ_IRQ_CRYPTO1F);
+ syslog(LOG_ERR, "ba414e: timeout, status %08" PRIx32 "\n",
+ getreg32(BA414E_PKSTATUS));
+ return -ETIMEDOUT;
+ }
+
+ return OK;
+}
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_SELFTEST
+static void ba414e_selftest(void);
+#endif
+
+/* Take the engine; load the microcode on first use */
+
+static int ba414e_lock(void)
+{
+ FAR const uint32_t *ucode;
+
+ nxrmutex_lock(&g_ba414e_lock);
+ if (g_ba414e_loaded)
+ {
+ return OK;
+ }
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_UCODE_FILE
+ ucode = ba414e_read_ucode();
+ if (ucode == NULL)
+ {
+ nxrmutex_unlock(&g_ba414e_lock);
+ return -ENOENT;
+ }
+#else
+ ucode = g_ba414e_ucode;
+#endif
+
+ putreg32(0, BA414E_PKCONTROL);
+ ba414e_load_ucode(ucode);
+ ba414e_clear_scm();
+ g_ba414e_loaded = true;
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_UCODE_FILE
+ kmm_free((FAR void *)ucode);
+#endif
+
+ syslog(LOG_INFO, "ba414e: microcode loaded\n");
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_SELFTEST
+ ba414e_selftest();
+#endif
+
+ return OK;
+}
+
+static int ba414e_modop(int opcode, FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p, int len)
+{
+ int opsize = ba414e_opsize(len);
+ int ret;
+
+ if (len <= 0 || len > BA414E_MAX_BYTES)
+ {
+ return -EINVAL;
+ }
+
+ ret = ba414e_lock();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ba414e_setup(opcode, opsize, PKCONFIG_OPPTRA(MOD_SLOT_A) |
+ PKCONFIG_OPPTRB(MOD_SLOT_B) | PKCONFIG_OPPTRC(MOD_SLOT_C));
+ ba414e_write_slot(MOD_SLOT_P, p, len, opsize * 8);
+ ba414e_write_slot(MOD_SLOT_A, a, len, opsize * 8);
+ ba414e_write_slot(MOD_SLOT_B, b, len, opsize * 8);
+
+ ret = ba414e_run();
+ if (ret == OK)
+ {
+ if (g_ba414e_fault)
+ {
+ ret = -EIO;
+ }
+ else
+ {
+ ba414e_read_slot(MOD_SLOT_C, c, len);
+ }
+ }
+
+ nxrmutex_unlock(&g_ba414e_lock);
+ return ret;
+}
+
+/* Common part of the ECC primitives: load the curve and P1 */
+
+static void ba414e_ecc_setup(FAR const struct ba414e_curve_s *curve,
+ int opcode, uint32_t config,
+ FAR const uint8_t *px, FAR const uint8_t *py)
+{
+ int opsize = ba414e_opsize(curve->len);
+ int slotlen = opsize * 8;
+
+ ba414e_setup(opcode, opsize, config);
+ ba414e_write_slot(ECC_SLOT_P, curve->p, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_N, curve->n, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_GX, curve->gx, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_GY, curve->gy, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_A, curve->a, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_B, curve->b, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_P1X, px, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_P1Y, py, curve->len, slotlen);
+}
+
+/* Run an ECC operation with result P3 */
+
+static int ba414e_ecc_finish(FAR const struct ba414e_curve_s *curve,
+ FAR uint8_t *rx, FAR uint8_t *ry)
+{
+ int ret = ba414e_run();
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* [EX] PXINF flags the point at infinity, also on the fault path */
+
+ if (g_ba414e_status & PKSTATUS_PXINF)
+ {
+ return BA414E_POINT_AT_INF;
+ }
+
+ if (g_ba414e_fault)
+ {
+ return -EIO;
+ }
+
+ ba414e_read_slot(ECC_SLOT_P3X, rx, curve->len);
+ ba414e_read_slot(ECC_SLOT_P3Y, ry, curve->len);
+ return BA414E_OK;
+}
+
+#ifdef CONFIG_PIC32MZ_W1_BA414E_SELFTEST
+static inline uint32_t ba414e_count(void)
+{
+ uint32_t count;
+
+ __asm__ __volatile__("mfc0 %0, $9" : "=r"(count));
+ return count;
+}
+
+static void ba414e_report(FAR const char *name, bool ok, uint32_t start)
+{
+ /* CP0 Count runs at SYSCLK / 2 */
+
+ syslog(LOG_INFO, "ba414e: %-8s %s %6" PRIu32 " us\n", name,
+ ok ? "ok " : "FAIL",
+ (ba414e_count() - start) / (BOARD_CPU_CLOCK / 2000000));
+}
+
+static void ba414e_selftest(void)
+{
+ FAR const struct ba414e_curve_s *c = &g_ba414e_p256;
+ static const uint8_t k[32] =
+ {
+ 0x78, 0x56, 0x34, 0x12, 0xef, 0xbe, 0xad, 0xde
+ };
+
+ uint8_t one[32];
+ uint8_t x[32];
+ uint8_t y[32];
+ uint8_t e[32];
+ uint32_t t;
+ int ret;
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_check(c, c->gx, c->gy);
+ ba414e_report("oncurve", ret == BA414E_OK, t);
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_check(c, c->gx, c->gx);
+ ba414e_report("offcurve", ret == BA414E_NOT_ON_CURVE, t);
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_add(c, x, y, c->gx, c->gy, c->gx, c->gy);
+ ba414e_report("double", ret == BA414E_OK &&
+ memcmp(x, g_st_2gx, 32) == 0 &&
+ memcmp(y, g_st_2gy, 32) == 0, t);
+
+ /* 2G + G + G = 4G */
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_add(c, x, y, g_st_2gx, g_st_2gy, c->gx, c->gy);
+ if (ret == BA414E_OK)
+ {
+ ret = pic32mz_ba414e_ecc_add(c, x, y, x, y, c->gx, c->gy);
+ }
+
+ ba414e_report("add", ret == BA414E_OK &&
+ memcmp(x, g_st_4gx, 32) == 0, t);
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_mul(c, x, y, c->gx, c->gy, k);
+ ba414e_report("mul", ret == BA414E_OK &&
+ memcmp(x, g_st_kgx, 32) == 0 &&
+ memcmp(y, g_st_kgy, 32) == 0, t);
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_ecc_mul(c, x, y, c->gx, c->gy, c->n);
+ ba414e_report("mul n", ret == BA414E_POINT_AT_INF, t);
+
+ /* 3^(p-2) mod p, then 3 * 3^-1 mod p = 1 */
+
+ memset(x, 0, sizeof(x));
+ x[0] = 3;
+ memcpy(e, c->p, 32);
+ e[0] -= 2;
+ t = ba414e_count();
+ ret = pic32mz_ba414e_modexp(y, x, e, c->p, 32);
+ ba414e_report("modexp", ret == BA414E_OK &&
+ memcmp(y, g_st_inv3, 32) == 0, t);
+
+ memset(one, 0, sizeof(one));
+ one[0] = 1;
+ t = ba414e_count();
+ ret = pic32mz_ba414e_modmul(e, x, g_st_inv3, c->p, 32);
+ ba414e_report("modmul", ret == BA414E_OK &&
+ memcmp(e, one, 32) == 0, t);
+
+ /* (p - 1) + 1 = 0, 0 - 1 = p - 1 */
+
+ memcpy(e, c->p, 32);
+ e[0] -= 1;
+ t = ba414e_count();
+ ret = pic32mz_ba414e_modadd(x, e, one, c->p, 32);
+ memset(y, 0, sizeof(y));
+ ba414e_report("modadd", ret == BA414E_OK && memcmp(x, y, 32) == 0, t);
+
+ t = ba414e_count();
+ ret = pic32mz_ba414e_modsub(x, y, one, c->p, 32);
+ ba414e_report("modsub", ret == BA414E_OK && memcmp(x, e, 32) == 0, t);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int pic32mz_ba414e_initialize(void)
+{
+ if (getreg32(PIC32MZ_PMD1) & PMD1_BA414MD)
+ {
+ syslog(LOG_ERR, "ba414e: disabled in PMD1\n");
+ return -ENODEV;
+ }
+
+ putreg32(0, BA414E_PKCONTROL);
+ irq_attach(PIC32MZ_IRQ_CRYPTO1, ba414e_isr, NULL);
+ irq_attach(PIC32MZ_IRQ_CRYPTO1F, ba414e_isr, NULL);
+
+ /* The microcode is loaded on first use, when its file system may be
+ * mounted.
+ */
+
+ return OK;
+}
+
+int pic32mz_ba414e_modadd(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len)
+{
+ return ba414e_modop(OPC_MOD_ADD, c, a, b, p, len);
+}
+
+int pic32mz_ba414e_modsub(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len)
+{
+ return ba414e_modop(OPC_MOD_SUB, c, a, b, p, len);
+}
+
+int pic32mz_ba414e_modmul(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len)
+{
+ return ba414e_modop(OPC_MOD_MULT, c, a, b, p, len);
+}
+
+int pic32mz_ba414e_modexp(FAR uint8_t *c, FAR const uint8_t *m,
+ FAR const uint8_t *e, FAR const uint8_t *n,
+ int len)
+{
+ int opsize = ba414e_opsize(len);
+ int ret;
+
+ if (len <= 0 || len > BA414E_MAX_BYTES)
+ {
+ return -EINVAL;
+ }
+
+ ret = ba414e_lock();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ba414e_setup(OPC_MOD_EXP, opsize, PKCONFIG_OPPTRA(EXP_SLOT_M) |
+ PKCONFIG_OPPTRB(EXP_SLOT_E) | PKCONFIG_OPPTRC(EXP_SLOT_C));
+ ba414e_write_slot(EXP_SLOT_N, n, len, opsize * 8);
+ ba414e_write_slot(EXP_SLOT_M, m, len, opsize * 8);
+ ba414e_write_slot(EXP_SLOT_E, e, len, opsize * 8);
+
+ ret = ba414e_run();
+ if (ret == OK)
+ {
+ if (g_ba414e_fault)
+ {
+ ret = -EIO;
+ }
+ else
+ {
+ ba414e_read_slot(EXP_SLOT_C, c, len);
+ }
+ }
+
+ nxrmutex_unlock(&g_ba414e_lock);
+ return ret;
+}
+
+int pic32mz_ba414e_ecc_add(FAR const struct ba414e_curve_s *curve,
+ FAR uint8_t *rx, FAR uint8_t *ry,
+ FAR const uint8_t *px, FAR const uint8_t *py,
+ FAR const uint8_t *qx, FAR const uint8_t *qy)
+{
+ int slotlen = ba414e_opsize(curve->len) * 8;
+ int ret;
+
+ ret = ba414e_lock();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* [EX] The addition primitive needs distinct points: use the doubling
+ * primitive for P + P.
+ */
+
+ if (memcmp(px, qx, curve->len) == 0 && memcmp(py, qy, curve->len) == 0)
+ {
+ ba414e_ecc_setup(curve, OPC_ECC_DOUBLE,
+ PKCONFIG_OPPTRA(ECC_SLOT_P1X) |
+ PKCONFIG_OPPTRC(ECC_SLOT_P3X), px, py);
+ }
+ else
+ {
+ ba414e_ecc_setup(curve, OPC_ECC_ADD,
+ PKCONFIG_OPPTRA(ECC_SLOT_P1X) |
+ PKCONFIG_OPPTRB(ECC_SLOT_P2X) |
+ PKCONFIG_OPPTRC(ECC_SLOT_P3X), px, py);
+ ba414e_write_slot(ECC_SLOT_P2X, qx, curve->len, slotlen);
+ ba414e_write_slot(ECC_SLOT_P2Y, qy, curve->len, slotlen);
+ }
+
+ ret = ba414e_ecc_finish(curve, rx, ry);
+ nxrmutex_unlock(&g_ba414e_lock);
+ return ret;
+}
+
+int pic32mz_ba414e_ecc_mul(FAR const struct ba414e_curve_s *curve,
+ FAR uint8_t *rx, FAR uint8_t *ry,
+ FAR const uint8_t *px, FAR const uint8_t *py,
+ FAR const uint8_t *k)
+{
+ int slotlen = ba414e_opsize(curve->len) * 8;
+ int ret;
+
+ ret = ba414e_lock();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ba414e_ecc_setup(curve, OPC_ECC_MULT,
+ PKCONFIG_OPPTRA(ECC_SLOT_P1X) |
+ PKCONFIG_OPPTRB(ECC_SLOT_K) |
+ PKCONFIG_OPPTRC(ECC_SLOT_P3X), px, py);
+ ba414e_write_slot(ECC_SLOT_K, k, curve->len, slotlen);
+
+ ret = ba414e_ecc_finish(curve, rx, ry);
+ nxrmutex_unlock(&g_ba414e_lock);
+ return ret;
+}
+
+int pic32mz_ba414e_ecc_check(FAR const struct ba414e_curve_s *curve,
+ FAR const uint8_t *px, FAR const uint8_t *py)
+{
+ int ret;
+
+ ret = ba414e_lock();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ba414e_ecc_setup(curve, OPC_ECC_ONCURVE,
+ PKCONFIG_OPPTRA(ECC_SLOT_P1X), px, py);
+
+ ret = ba414e_run();
+ if (ret == OK)
+ {
+ /* [EX] PXNOC takes precedence over the fault indication */
+
+ if (g_ba414e_status & PKSTATUS_PXNOC)
+ {
+ ret = BA414E_NOT_ON_CURVE;
+ }
+ else if (g_ba414e_fault)
+ {
+ ret = -EIO;
+ }
+ }
+
+ nxrmutex_unlock(&g_ba414e_lock);
+ return ret;
+}
diff --git a/arch/mips/src/pic32mz/pic32mz_ba414e.h b/arch/mips/src/pic32mz/pic32mz_ba414e.h
new file mode 100644
index 00000000000..3531105f988
--- /dev/null
+++ b/arch/mips/src/pic32mz/pic32mz_ba414e.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+ * arch/mips/src/pic32mz/pic32mz_ba414e.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_BA414E_H
+#define __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_BA414E_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Largest operand: 512 bits */
+
+#define BA414E_MAX_BYTES 64
+
+/* Operation results (beyond negated errno values) */
+
+#define BA414E_OK 0
+#define BA414E_POINT_AT_INF 1 /* ECC result is the point at infinity */
+#define BA414E_NOT_ON_CURVE 2 /* Point is not on the curve */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Short Weierstrass curve y^2 = x^3 + ax + b over GF(p). All values are
+ * little endian, 'len' bytes long.
+ */
+
+struct ba414e_curve_s
+{
+ uint8_t len;
+ FAR const uint8_t *p;
+ FAR const uint8_t *n;
+ FAR const uint8_t *gx;
+ FAR const uint8_t *gy;
+ FAR const uint8_t *a;
+ FAR const uint8_t *b;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* NIST P-256 (FIPS 186-4 D.1.2.3), little endian */
+
+extern const struct ba414e_curve_s g_ba414e_p256;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* All operands and results are little endian, 'len' bytes (at most
+ * BA414E_MAX_BYTES). The functions block until the engine is done and
+ * return BA414E_OK (or one of the ECC results above) or a negated errno.
+ */
+
+int pic32mz_ba414e_initialize(void);
+
+int pic32mz_ba414e_modadd(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len);
+int pic32mz_ba414e_modsub(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len);
+int pic32mz_ba414e_modmul(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len);
+int pic32mz_ba414e_modexp(FAR uint8_t *c, FAR const uint8_t *m,
+ FAR const uint8_t *e, FAR const uint8_t *n,
+ int len);
+
+int pic32mz_ba414e_ecc_add(FAR const struct ba414e_curve_s *curve,
+ FAR uint8_t *rx, FAR uint8_t *ry,
+ FAR const uint8_t *px, FAR const uint8_t *py,
+ FAR const uint8_t *qx, FAR const uint8_t *qy);
+int pic32mz_ba414e_ecc_mul(FAR const struct ba414e_curve_s *curve,
+ FAR uint8_t *rx, FAR uint8_t *ry,
+ FAR const uint8_t *px, FAR const uint8_t *py,
+ FAR const uint8_t *k);
+int pic32mz_ba414e_ecc_check(FAR const struct ba414e_curve_s *curve,
+ FAR const uint8_t *px, FAR const uint8_t *py);
+
+#endif /* __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_BA414E_H */
diff --git a/arch/mips/src/pic32mz/pic32mz_w1_wlan.c b/arch/mips/src/pic32mz/pic32mz_w1_wlan.c
index 7bff1abbb37..e7e25163fbb 100644
--- a/arch/mips/src/pic32mz/pic32mz_w1_wlan.c
+++ b/arch/mips/src/pic32mz/pic32mz_w1_wlan.c
@@ -26,6 +26,7 @@
* kernel thread, three RF interrupts and a byte-coded configuration
* protocol ("WIDs"). The network device is a netdev_upperhalf lower half
* with the wireless operations used by wapi (scan, essid, psk, mode, freq).
+ * WPA3-Personal needs the BA414E engine (pic32mz_ba414e.c).
*
* Every hardware or library fact below is tagged with where it comes from:
*
@@ -73,6 +74,9 @@
#include "mips_internal.h"
#include "hardware/pic32mzw1_pmuclk.h"
#include "pic32mz_w1_wlan.h"
+#ifdef CONFIG_PIC32MZ_W1_BA414E
+# include "pic32mz_ba414e.h"
+#endif
/****************************************************************************
* Pre-processor Definitions
@@ -141,6 +145,7 @@
#define WID_GET_SCAN_RESULTS 0x3034
#define WID_REG_DOMAIN 0x4010
#define WID_STA_JOIN_INFO 0x4008
+#define WID_RSNA_PASSWORD 0x4012
#define WID_SSID 0x4020
#define WID_TYPE(w) ((w) >> 12)
@@ -161,7 +166,9 @@
#define DOT11I_CCMP128 0x0040
#define DOT11I_TKIP 0x0080
#define DOT11I_BIPCMAC128 0x0100
+#define DOT11I_MFP_REQUIRED 0x0200
#define DOT11I_PSK 0x0800
+#define DOT11I_SAE 0x1000
#define DOT11I_AP 0x8000
/* [EX] Harmony's WPA2-Personal and WPA/WPA2-Personal settings */
@@ -172,6 +179,14 @@
#define DOT11I_WPAWPA2_PERSONAL \
(DOT11I_WPA2_PERSONAL | DOT11I_WPAIE | DOT11I_TKIP)
+/* [EX] Harmony's WPA3-Personal settings (SAE, management frame protection
+ * required)
+ */
+
+#define DOT11I_WPA3_PERSONAL \
+ (DOT11I_PRIVACY | DOT11I_RSNE | DOT11I_CCMP128 | DOT11I_BIPCMAC128 | \
+ DOT11I_MFP_REQUIRED | DOT11I_SAE)
+
/* Soft-AP channel when none was requested */
#define WLAN_AP_CHANNEL 1
@@ -188,6 +203,8 @@
#define WLAN_RX_QUOTA 8
#define WLAN_TX_QUOTA 4
+#define WLAN_CRYPTO_DEFER_MAX 8
+
#define IW_EVENT_SIZE(field) \
(offsetof(struct iw_event, u) + sizeof(((union iwreq_data *)0)->field))
@@ -217,6 +234,13 @@ struct wid_msg_s
char op; /* 'W' write or 'Q' query */
};
+struct wlan_crypto_defer_s
+{
+ wlan_crypto_cb_t cb;
+ int result;
+ uintptr_t context;
+};
+
enum wlan_scan_e
{
WLAN_SCAN_IDLE = 0,
@@ -241,6 +265,12 @@ struct pic32mz_wlan_s
bool ready;
uint8_t mac[6];
+ /* Deferred crypto completion callbacks (ring) */
+
+ struct wlan_crypto_defer_s defer[WLAN_CRYPTO_DEFER_MAX];
+ uint8_t defer_head;
+ uint8_t defer_tail;
+
/* Network device */
spinlock_t rxlock;
@@ -801,6 +831,30 @@ static void wlan_send_init(void)
}
}
+/* Run the deferred crypto callbacks; called with the library lock held */
+
+static void wlan_crypto_run(void)
+{
+ struct wlan_crypto_defer_s d;
+ irqstate_t flags;
+
+ for (; ; )
+ {
+ flags = enter_critical_section();
+ if (g_wlan.defer_head == g_wlan.defer_tail)
+ {
+ leave_critical_section(flags);
+ break;
+ }
+
+ d = g_wlan.defer[g_wlan.defer_tail];
+ g_wlan.defer_tail = (g_wlan.defer_tail + 1) % WLAN_CRYPTO_DEFER_MAX;
+ leave_critical_section(flags);
+
+ d.cb(d.result, d.context);
+ }
+}
+
static int wlan_thread(int argc, FAR char *argv[])
{
FAR sq_entry_t *entry;
@@ -827,6 +881,7 @@ static int wlan_thread(int argc, FAR char *argv[])
wdrv_pic32mzw_process_cfg_message(wlan_data(entry));
}
+ wlan_crypto_run();
wdrv_pic32mzw_mac_controller_task();
nxmutex_unlock(&g_wlan.lock);
@@ -946,6 +1001,12 @@ static int wlan_dot11i(FAR uint32_t *dot11i)
*dot11i = DOT11I_WPA2_PERSONAL;
break;
+#ifdef CONFIG_PIC32MZ_W1_BA414E
+ case IW_AUTH_WPA_VERSION_WPA3:
+ *dot11i = DOT11I_WPA3_PERSONAL;
+ break;
+#endif
+
default:
wlerr("WPA version %" PRIu32 " not supported\n", g_wlan.wpaver);
return -ENOTSUP;
@@ -987,6 +1048,11 @@ static int wlan_apstart(uint32_t dot11i)
wid_data(&msg, WID_11I_PSK, g_wlan.psk, g_wlan.psklen);
}
+ if (dot11i & DOT11I_SAE)
+ {
+ wid_data(&msg, WID_RSNA_PASSWORD, g_wlan.psk, g_wlan.psklen);
+ }
+
wid_value(&msg, WID_11G_OPERATING_MODE, 2);
wid_value(&msg, WID_ACK_POLICY, 0);
wid_value(&msg, WID_11N_ENABLE, 1);
@@ -1045,6 +1111,11 @@ static int wlan_connect(FAR struct netdev_lowerhalf_s *dev)
wid_data(&msg, WID_11I_PSK, g_wlan.psk, g_wlan.psklen);
}
+ if (dot11i & DOT11I_SAE)
+ {
+ wid_data(&msg, WID_RSNA_PASSWORD, g_wlan.psk, g_wlan.psklen);
+ }
+
wid_value(&msg, WID_11G_OPERATING_MODE, 2);
wid_value(&msg, WID_ACK_POLICY, 0);
wid_value(&msg, WID_11N_ENABLE, 1);
@@ -1617,6 +1688,39 @@ int pic32mzw1_putchar(int c)
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Name: pic32mz_wlan_crypto_defer
+ *
+ * Description:
+ * Queue a crypto completion callback; the WLAN thread runs it with the
+ * library lock held ([EX] as Harmony's DRV_PIC32MZW_CryptoCallbackPush()).
+ *
+ ****************************************************************************/
+
+void pic32mz_wlan_crypto_defer(wlan_crypto_cb_t cb, int result,
+ uintptr_t context)
+{
+ irqstate_t flags;
+ uint8_t next;
+
+ flags = enter_critical_section();
+ next = (g_wlan.defer_head + 1) % WLAN_CRYPTO_DEFER_MAX;
+ if (next == g_wlan.defer_tail)
+ {
+ leave_critical_section(flags);
+ wlerr("crypto callback queue full\n");
+ return;
+ }
+
+ g_wlan.defer[g_wlan.defer_head].cb = cb;
+ g_wlan.defer[g_wlan.defer_head].result = result;
+ g_wlan.defer[g_wlan.defer_head].context = context;
+ g_wlan.defer_head = next;
+ leave_critical_section(flags);
+
+ nxsem_post(&g_wlan.evsem);
+}
+
/****************************************************************************
* Name: pic32mz_wlan_initialize
*
@@ -1645,6 +1749,14 @@ int pic32mz_wlan_initialize(void)
g_wlan.wpaver = IW_AUTH_WPA_VERSION_DISABLED;
+#ifdef CONFIG_PIC32MZ_W1_BA414E
+ ret = pic32mz_ba414e_initialize();
+ if (ret < 0)
+ {
+ return ret;
+ }
+#endif
+
/* [EX] Turn the WLAN LDO on */
modifyreg32(PIC32MZ_PMUCLKCTRL, PMUCLKCTRL_WLDOOFF, 0);
diff --git a/arch/mips/src/pic32mz/pic32mz_w1_wlan.h b/arch/mips/src/pic32mz/pic32mz_w1_wlan.h
index 5493f8ffefe..d7c084130f1 100644
--- a/arch/mips/src/pic32mz/pic32mz_w1_wlan.h
+++ b/arch/mips/src/pic32mz/pic32mz_w1_wlan.h
@@ -40,6 +40,10 @@
* in pic32mz_w1_wlan.c.
*/
+/* Completion callback of the crypto services (DRV_PIC32MZW_CRYPTO_CB) */
+
+typedef CODE void (*wlan_crypto_cb_t)(int result, uintptr_t context);
+
struct pic32mz_wlan_init_s
{
int alarm_1ms;
@@ -97,4 +101,9 @@ int pic32mzw1_putchar(int c);
int pic32mz_wlan_initialize(void);
+/* Run a crypto completion callback later from the WLAN thread */
+
+void pic32mz_wlan_crypto_defer(wlan_crypto_cb_t cb, int result,
+ uintptr_t context);
+
#endif /* __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_W1_WLAN_H */
diff --git a/arch/mips/src/pic32mz/pic32mz_w1_wlan_crypto.c b/arch/mips/src/pic32mz/pic32mz_w1_wlan_crypto.c
index f426cca58a6..79328faa619 100644
--- a/arch/mips/src/pic32mz/pic32mz_w1_wlan_crypto.c
+++ b/arch/mips/src/pic32mz/pic32mz_w1_wlan_crypto.c
@@ -24,8 +24,15 @@
* ([EX] interface of drv_pic32mzw1_crypto.c, see pic32mz_w1_wlan.c for the
* tags). Random, hash and HMAC, all that WPA/WPA2-Personal needs, use
* NuttX's software crypto. The big number and elliptic curve operations
- * (WPA3-Personal), DES (MSCHAPv2) and TLS (enterprise) are not implemented
- * and report an error.
+ * of WPA3-Personal (SAE) use the BA414E engine (CONFIG_PIC32MZ_W1_BA414E),
+ * without it they report an error. DES (MSCHAPv2) and TLS (enterprise)
+ * are not implemented and report an error.
+ *
+ * [EX] When the library passes a completion callback, the operation must
+ * return "pending" and the callback runs later from the WLAN thread, with
+ * the library lock held (Harmony's DRV_PIC32MZW_CryptoCallbackPush()). The
+ * engine is fast, so the operation completes here and only the callback is
+ * deferred.
*/
/****************************************************************************
@@ -45,6 +52,9 @@
#include <crypto/sha2.h>
#include "pic32mz_w1_wlan.h"
+#ifdef CONFIG_PIC32MZ_W1_BA414E
+# include "pic32mz_ba414e.h"
+#endif
/****************************************************************************
* Pre-processor Definitions
@@ -62,9 +72,18 @@
/* [EX] Return codes (DRV_PIC32MZW_CRYPTO_RETURN_T) */
#define WLAN_CRYPTO_COMPLETE 0
+#define WLAN_CRYPTO_PENDING 1
#define WLAN_CRYPTO_INVALID 3
#define WLAN_CRYPTO_ERROR 4
+/* [EX] Curve identifier of P-256 (DRV_PIC32MZW_CRYPTO_CURVE_P256R1) */
+
+#define WLAN_CURVE_P256 2
+
+/* Largest big number handled by BigIntMod */
+
+#define WLAN_BIGINT_MAX 128
+
#define WLAN_HASH_MAXBLOCK 128
#define WLAN_HASH_MAXDIGEST 64
@@ -349,8 +368,351 @@ int DRV_PIC32MZW_Crypto_HMAC(FAR const uint8_t *key, uint16_t keylen,
return WLAN_CRYPTO_COMPLETE;
}
+#ifdef CONFIG_PIC32MZ_W1_BA414E
+
+/* Big integer and elliptic curve operations ([EX] interface of Harmony's
+ * drv_pic32mzw1_crypto.c). Values are 'len' bytes, big or little endian
+ * as requested; inputs and outputs may overlap. The BA414E primitives
+ * take little endian values.
+ */
+
+static void wlan_to_le(FAR uint8_t *dst, FAR const uint8_t *src, int len,
+ bool is_be)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ dst[i] = is_be ? src[len - 1 - i] : src[i];
+ }
+}
+
+#define wlan_from_le(dst, src, len, is_be) wlan_to_le(dst, src, len, is_be)
+
+/* Report a result: complete now, or pending with a deferred callback */
+
+static int wlan_crypto_done(int ret, wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ if (ret < 0)
+ {
+ return WLAN_CRYPTO_ERROR;
+ }
+
+ if (cb == NULL)
+ {
+ return WLAN_CRYPTO_COMPLETE;
+ }
+
+ pic32mz_wlan_crypto_defer(cb, WLAN_CRYPTO_COMPLETE, ctx);
+ return WLAN_CRYPTO_PENDING;
+}
+
+/* out = ain mod m, by shift and subtract. In software, as Harmony does:
+ * ain may be longer than the modulus.
+ */
+
+int DRV_PIC32MZW_Crypto_BigIntMod(FAR const uint8_t *mod, FAR uint8_t *out,
+ FAR const uint8_t *ain, uint16_t ain_len,
+ uint16_t len, bool is_be,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ uint8_t m[WLAN_BIGINT_MAX + 1];
+ uint8_t a[WLAN_BIGINT_MAX];
+ uint8_t r[WLAN_BIGINT_MAX + 1];
+ int bit;
+ int v;
+ int i;
+ int c;
+
+ if (mod == NULL || out == NULL || ain == NULL || len == 0 ||
+ len > WLAN_BIGINT_MAX || ain_len > WLAN_BIGINT_MAX)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ wlan_to_le(m, mod, len, is_be);
+ m[len] = 0;
+ wlan_to_le(a, ain, ain_len, is_be);
+ memset(r, 0, sizeof(r));
+
+ for (bit = ain_len * 8 - 1; bit >= 0; bit--)
+ {
+ /* r = 2r + bit */
+
+ c = (a[bit / 8] >> (bit % 8)) & 1;
+ for (i = 0; i <= len; i++)
+ {
+ v = (r[i] << 1) | c;
+ r[i] = v & 0xff;
+ c = v >> 8;
+ }
+
+ /* if (r >= m) r -= m */
+
+ i = len;
+ while (i >= 0 && r[i] == m[i])
+ {
+ i--;
+ }
+
+ if (i < 0 || r[i] > m[i])
+ {
+ c = 0;
+ for (i = 0; i <= len; i++)
+ {
+ v = r[i] - m[i] - c;
+ r[i] = v & 0xff;
+ c = v < 0;
+ }
+ }
+ }
+
+ wlan_from_le(out, r, len, is_be);
+ return wlan_crypto_done(OK, cb, ctx);
+}
+
+typedef CODE int (*wlan_modop_t)(FAR uint8_t *c, FAR const uint8_t *a,
+ FAR const uint8_t *b, FAR const uint8_t *p,
+ int len);
+
+static int wlan_modop(wlan_modop_t op, FAR const uint8_t *mod,
+ FAR uint8_t *out, FAR const uint8_t *ain,
+ FAR const uint8_t *bin, uint16_t len, bool is_be,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ uint8_t p[BA414E_MAX_BYTES];
+ uint8_t a[BA414E_MAX_BYTES];
+ uint8_t b[BA414E_MAX_BYTES];
+ uint8_t c[BA414E_MAX_BYTES];
+ int ret;
+
+ if (mod == NULL || out == NULL || ain == NULL || bin == NULL ||
+ len == 0 || len > BA414E_MAX_BYTES)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ wlan_to_le(p, mod, len, is_be);
+ wlan_to_le(a, ain, len, is_be);
+ wlan_to_le(b, bin, len, is_be);
+
+ ret = op(c, a, b, p, len);
+ if (ret >= 0)
+ {
+ wlan_from_le(out, c, len, is_be);
+ }
+
+ return wlan_crypto_done(ret, cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_BigIntModAdd(FAR const uint8_t *mod,
+ FAR uint8_t *out,
+ FAR const uint8_t *ain,
+ FAR const uint8_t *bin, uint16_t len,
+ bool is_be, wlan_crypto_cb_t cb,
+ uintptr_t ctx)
+{
+ return wlan_modop(pic32mz_ba414e_modadd, mod, out, ain, bin, len, is_be,
+ cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_BigIntModSubtract(FAR const uint8_t *mod,
+ FAR uint8_t *out,
+ FAR const uint8_t *ain,
+ FAR const uint8_t *bin,
+ uint16_t len, bool is_be,
+ wlan_crypto_cb_t cb,
+ uintptr_t ctx)
+{
+ return wlan_modop(pic32mz_ba414e_modsub, mod, out, ain, bin, len, is_be,
+ cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_BigIntModMultiply(FAR const uint8_t *mod,
+ FAR uint8_t *out,
+ FAR const uint8_t *ain,
+ FAR const uint8_t *bin,
+ uint16_t len, bool is_be,
+ wlan_crypto_cb_t cb,
+ uintptr_t ctx)
+{
+ return wlan_modop(pic32mz_ba414e_modmul, mod, out, ain, bin, len, is_be,
+ cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_BigIntModExponentiate(FAR const uint8_t *mod,
+ FAR uint8_t *out,
+ FAR const uint8_t *base,
+ FAR const uint8_t *exp,
+ uint16_t len, bool is_be,
+ wlan_crypto_cb_t cb,
+ uintptr_t ctx)
+{
+ return wlan_modop(pic32mz_ba414e_modexp, mod, out, base, exp, len, is_be,
+ cb, ctx);
+}
+
+static FAR const struct ba414e_curve_s *wlan_curve(int curve)
+{
+ return curve == WLAN_CURVE_P256 ? &g_ba414e_p256 : NULL;
+}
+
+/* [EX] Returns the curve's field (little endian), or NULL for an unknown
+ * curve
+ */
+
+FAR const uint8_t *DRV_PIC32MZW_Crypto_ECCGetField(int curve)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+
+ return c != NULL ? c->p : NULL;
+}
+
+int DRV_PIC32MZW_Crypto_ECCIsOnCurve(int curve, FAR bool *notoncurve,
+ FAR const uint8_t *px,
+ FAR const uint8_t *py, bool is_be,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+ uint8_t x[BA414E_MAX_BYTES];
+ uint8_t y[BA414E_MAX_BYTES];
+ int ret;
+
+ if (c == NULL || notoncurve == NULL || px == NULL || py == NULL)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ wlan_to_le(x, px, c->len, is_be);
+ wlan_to_le(y, py, c->len, is_be);
+
+ ret = pic32mz_ba414e_ecc_check(c, x, y);
+ *notoncurve = (ret == BA414E_NOT_ON_CURVE);
+ return wlan_crypto_done(ret, cb, ctx);
+}
+
+/* [EX] out = a * in and out = in + b (mod p), little endian */
+
+int DRV_PIC32MZW_Crypto_ECCBigIntModMultByA(int curve, FAR uint8_t *out,
+ FAR const uint8_t *in,
+ wlan_crypto_cb_t cb,
+ uintptr_t ctx)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+
+ if (c == NULL)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ return wlan_modop(pic32mz_ba414e_modmul, c->p, out, in, c->a, c->len,
+ false, cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_ECCBigIntModAddB(int curve, FAR uint8_t *out,
+ FAR const uint8_t *in,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+
+ if (c == NULL)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ return wlan_modop(pic32mz_ba414e_modadd, c->p, out, in, c->b, c->len,
+ false, cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_ECCAdd(int curve, FAR bool *is_infinity,
+ FAR uint8_t *outx, FAR uint8_t *outy,
+ FAR const uint8_t *pinx,
+ FAR const uint8_t *piny,
+ FAR const uint8_t *qinx,
+ FAR const uint8_t *qiny, bool is_be,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+ uint8_t px[BA414E_MAX_BYTES];
+ uint8_t py[BA414E_MAX_BYTES];
+ uint8_t qx[BA414E_MAX_BYTES];
+ uint8_t qy[BA414E_MAX_BYTES];
+ uint8_t rx[BA414E_MAX_BYTES];
+ uint8_t ry[BA414E_MAX_BYTES];
+ int ret;
+
+ if (c == NULL || is_infinity == NULL || outx == NULL || outy == NULL ||
+ pinx == NULL || piny == NULL || qinx == NULL || qiny == NULL)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ memset(px, 0, sizeof(px));
+ memset(py, 0, sizeof(py));
+ memset(qx, 0, sizeof(qx));
+ memset(qy, 0, sizeof(qy));
+
+ wlan_to_le(px, pinx, c->len, is_be);
+ wlan_to_le(py, piny, c->len, is_be);
+ wlan_to_le(qx, qinx, c->len, is_be);
+ wlan_to_le(qy, qiny, c->len, is_be);
+
+ ret = pic32mz_ba414e_ecc_add(c, rx, ry, px, py, qx, qy);
+ *is_infinity = (ret == BA414E_POINT_AT_INF);
+ if (ret == BA414E_OK)
+ {
+ wlan_from_le(outx, rx, c->len, is_be);
+ wlan_from_le(outy, ry, c->len, is_be);
+ }
+
+ return wlan_crypto_done(ret, cb, ctx);
+}
+
+int DRV_PIC32MZW_Crypto_ECCMultiply(int curve, FAR bool *is_infinity,
+ FAR uint8_t *outx, FAR uint8_t *outy,
+ FAR const uint8_t *pinx,
+ FAR const uint8_t *piny,
+ FAR const uint8_t *kin, bool is_be,
+ wlan_crypto_cb_t cb, uintptr_t ctx)
+{
+ FAR const struct ba414e_curve_s *c = wlan_curve(curve);
+ uint8_t px[BA414E_MAX_BYTES];
+ uint8_t py[BA414E_MAX_BYTES];
+ uint8_t k[BA414E_MAX_BYTES];
+ uint8_t rx[BA414E_MAX_BYTES];
+ uint8_t ry[BA414E_MAX_BYTES];
+ int ret;
+
+ if (c == NULL || is_infinity == NULL || outx == NULL || outy == NULL ||
+ pinx == NULL || piny == NULL || kin == NULL)
+ {
+ return WLAN_CRYPTO_INVALID;
+ }
+
+ memset(px, 0, sizeof(px));
+ memset(py, 0, sizeof(py));
+ memset(k, 0, sizeof(k));
+
+ wlan_to_le(px, pinx, c->len, is_be);
+ wlan_to_le(py, piny, c->len, is_be);
+ wlan_to_le(k, kin, c->len, is_be);
+
+ ret = pic32mz_ba414e_ecc_mul(c, rx, ry, px, py, k);
+ *is_infinity = (ret == BA414E_POINT_AT_INF);
+ if (ret == BA414E_OK)
+ {
+ wlan_from_le(outx, rx, c->len, is_be);
+ wlan_from_le(outy, ry, c->len, is_be);
+ }
+
+ return wlan_crypto_done(ret, cb, ctx);
+}
+
+#endif /* CONFIG_PIC32MZ_W1_BA414E */
+
/* Not implemented: every call reports an error. The library only uses
- * them for WPA3-Personal (SAE), MSCHAPv2 and enterprise TLS.
+ * them for WPA3-Personal (SAE, without the BA414E), MSCHAPv2 and
+ * enterprise TLS.
*/
#define WLAN_CRYPTO_STUB(name) \
@@ -361,6 +723,8 @@ int DRV_PIC32MZW_Crypto_HMAC(FAR const uint8_t *key, uint16_t keylen,
}
WLAN_CRYPTO_STUB(DRV_PIC32MZW_Crypto_DES_Ecb_Crypt)
+
+#ifndef CONFIG_PIC32MZ_W1_BA414E
WLAN_CRYPTO_STUB(DRV_PIC32MZW_Crypto_BigIntMod)
WLAN_CRYPTO_STUB(DRV_PIC32MZW_Crypto_BigIntModAdd)
WLAN_CRYPTO_STUB(DRV_PIC32MZW_Crypto_BigIntModSubtract)
@@ -379,6 +743,7 @@ FAR const uint8_t *DRV_PIC32MZW_Crypto_ECCGetField(int curve)
syslog(LOG_ERR, "wlan: ECC not implemented\n");
return NULL;
}
+#endif
#define WLAN_TLS_STUB(name) \
int name(void) \