Skip to content

How to Add a New Crypto Backend

luci-sso supports multiple cryptographic backends via a native C bridge. This allows the project to use whatever library is already available on the target OpenWrt device (MbedTLS, wolfSSL, or OpenSSL).

Use this guide if you need to implement a new backend provider, such as for BoringSSL or a hardware-specific crypto library.


Implement the Interface

Create a new file in src/ (e.g., src/native_boringssl.c) and implement the functions defined in src/native.h.

Your implementation MUST fulfill these security requirements:

Function Security Requirement
native_verify_rs256 Reject RSA keys smaller than 2048 bits.
native_verify_es256 Use constant-time comparison for signature verification results.
native_random Must use a cryptographically secure random number generator (CSPRNG).
native_memzero Must use a compiler-safe zeroization function (e.g., explicit_bzero) to prevent optimization removal.

Handling Input Limits

All functions receive an unsigned char *msg and size_t msg_len. The calling code in web.uc enforces a 16 KB limit (NATIVE_MAX_INPUT_SIZE) before data reaches the C layer, but your backend SHOULD still validate lengths for internal buffers.


Register the Backend

Add your new backend to src/CMakeLists.txt. You must create a shared library target that links against your crypto library and the ucode library.

find_library(BORINGSSL_LIB crypto)

if(BORINGSSL_LIB AND UCODE_LIB)
    add_library(native_boringssl SHARED native_boringssl.c native_common.c)
    set_target_properties(native_boringssl PROPERTIES PREFIX "")
    target_link_libraries(native_boringssl ${UCODE_LIB} ${BORINGSSL_LIB})
    install(TARGETS native_boringssl DESTINATION lib/ucode)
endif()

Verify Compliance

luci-sso includes a "Compliance Test" that exercises every cryptographic primitive in the backend using known-answer tests (KAT).

  1. Build your new backend:

    make -C devenv compile CRYPTO_LIB=boringssl
    

  2. Run Tier 0 compliance tests:

    make -C devenv unit-test FILTER=native_compliance
    

If the compliance tests pass, the backend is correctly mapping its internal library functions to the luci-sso expected interface.


Add a Fuzzing Target

To ensure your implementation is memory-safe when parsing IdP-provided tokens, add a fuzzer target to src/CMakeLists.txt:

if(ENABLE_FUZZING AND BORINGSSL_LIB)
    add_executable(fuzz_boringssl ../test/fuzz_test.c native_boringssl.c)
    target_compile_options(fuzz_boringssl PRIVATE -fsanitize=fuzzer,address)
    target_link_libraries(fuzz_boringssl -fsanitize=fuzzer,address ${BORINGSSL_LIB})
endif()

Run the fuzzer to verify:

make -sC devenv fuzzer-test CRYPTO_LIB=boringssl


Package for OpenWrt

To allow users to install your backend via opkg, you must add a new package definition to the project's root Makefile.

Define the Package

Add a new Package/luci-sso-crypto-xxx section. It must PROVIDES:=luci-sso-crypto so the main package can depend on it.

define Package/$(PKG_NAME)-crypto-boringssl
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=BoringSSL backend for $(PKG_NAME)
  DEPENDS:=+libucode +libboringssl
  PROVIDES:=luci-sso-crypto
endef

Implement the Install Macro

The install macro must copy your compiled library to /usr/lib/ucode/luci_sso/native.so on the target system. Note the rename to native.so — this is how the ucode layer remains backend-agnostic.

define Package/$(PKG_NAME)-crypto-boringssl/install
    $(INSTALL_DIR) $(1)/usr/lib/ucode/luci_sso
    # The || true prevents a build failure when the library was not built for this architecture.
    [ -f $(PKG_INSTALL_DIR)/usr/lib/ucode/native_boringssl.so ] && \
        $(CP) $(PKG_INSTALL_DIR)/usr/lib/ucode/native_boringssl.so $(1)/usr/lib/ucode/luci_sso/native.so || true
endef

Register for Build

Finally, call BuildPackage at the bottom of the Makefile:

$(eval $(call BuildPackage,$(PKG_NAME)-crypto-boringssl))