Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/scripts/zephyr-4.x/zephyr-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@
# Examples:
# ./zephyr-test.sh -z v4.3.0
# ./zephyr-test.sh -r https://github.com/me/wolfPSA -b my-fix -z v4.4.0
# ./zephyr-test.sh -z v4.4.0 --wolfssl-ref v5.9.4-stable

set -euo pipefail

# Defaults point at the upstream wolfSSL org. The workflow sets -r/-b to the
# wolfPSA code under test and leaves the wolfSSL repo/ref at these upstream
# defaults. The --wolfssl-repo/--wolfssl-ref flags remain for pointing at a
# fork locally.
# wolfPSA code under test and --wolfssl-ref from its matrix (master plus the
# -stable tag wolfPSA is validated against), leaving the wolfSSL repo at the
# upstream default. --wolfssl-repo remains for pointing at a fork locally.
WOLFPSA_REPO="https://github.com/wolfSSL/wolfPSA"
WOLFPSA_BRANCH="master"
ZEPHYR_VERSION="v4.4.0"
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/build-config-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ on:

jobs:
build-config-matrix:
name: ${{ matrix.config.name }} / wolfSSL ${{ matrix.wolfssl-ref }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
# wolfSSL master plus the -stable tag wolfPSA is validated against.
wolfssl-ref: [ master, v5.9.4-stable ]
config:
- name: baseline
modifiers: ""
- name: md5
Expand Down Expand Up @@ -100,9 +103,9 @@ jobs:
sudo apt-get install -y build-essential

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build ${{ matrix.name }}
- name: Build ${{ matrix.config.name }}
env:
BUILD_TARGET: ${{ matrix.target || 'libwolfpsa.a' }}
run: ./build-test/build-variant.sh "${{ matrix.name }}" ${{ matrix.modifiers }}
BUILD_TARGET: ${{ matrix.config.target || 'libwolfpsa.a' }}
run: ./build-test/build-variant.sh "${{ matrix.config.name }}" ${{ matrix.config.modifiers }}
8 changes: 7 additions & 1 deletion .github/workflows/psa-compliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ on:
jobs:
psa-compliance:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# master tracks upstream; the -stable tag is the release wolfPSA is
# validated against. Bump it together with the wolfPSA version.
wolfssl-ref: [ master, v5.9.4-stable ]

steps:
- name: Check out wolfPSA
Expand All @@ -20,7 +26,7 @@ jobs:
sudo apt-get install -y build-essential cmake git

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build wolfPSA
run: make
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/test-psa-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ jobs:
# library itself; the sibling wolfSSL only provides the link.
test-ecc-curve-families:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# master tracks upstream; the -stable tag is the release wolfPSA is
# validated against. Bump it together with the wolfPSA version.
wolfssl-ref: [ master, v5.9.4-stable ]

steps:
- name: Check out wolfPSA
Expand All @@ -26,7 +32,7 @@ jobs:
sudo apt-get install -y build-essential autoconf automake libtool libtool-bin pkg-config

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build variant user_settings (Koblitz + Brainpool)
run: |
Expand Down Expand Up @@ -61,6 +67,12 @@ jobs:

test-psa-api:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# master tracks upstream; the -stable tag is the release wolfPSA is
# validated against. Bump it together with the wolfPSA version.
wolfssl-ref: [ master, v5.9.4-stable ]

steps:
- name: Check out wolfPSA
Expand All @@ -72,7 +84,7 @@ jobs:
sudo apt-get install -y build-essential autoconf automake libtool libtool-bin pkg-config

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build wolfPSA
run: make
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/wolfcrypt-benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ on:
jobs:
wolfcrypt-benchmark:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# master tracks upstream; the -stable tag is the release wolfPSA is
# validated against. Bump it together with the wolfPSA version.
wolfssl-ref: [ master, v5.9.4-stable ]

steps:
- name: Check out wolfPSA
Expand All @@ -18,7 +24,7 @@ jobs:
sudo apt-get install -y build-essential

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build wolfPSA
run: make
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/wolfssl-psa-client-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ on:
jobs:
wolfssl-psa-client-server:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# master tracks upstream; the -stable tag is the release wolfPSA is
# validated against. Bump it together with the wolfPSA version.
wolfssl-ref: [ master, v5.9.4-stable ]

steps:
- name: Check out wolfPSA
Expand All @@ -18,7 +24,7 @@ jobs:
sudo apt-get install -y build-essential autoconf automake libtool libtool-bin pkg-config

- name: Clone sibling wolfSSL
run: git clone --depth 1 https://github.com/wolfSSL/wolfssl ../wolfssl
run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl

- name: Build wolfPSA
run: make
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/zephyr-4.x.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ concurrency:

jobs:
build:
name: ${{ matrix.zephyr-ref }}
name: ${{ matrix.zephyr-ref }} / wolfSSL ${{ matrix.wolfssl-ref }}
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-22.04
timeout-minutes: 60
Expand All @@ -29,6 +29,8 @@ jobs:
matrix:
# 4.3 = the wolfPSA floor (upstream), 4.4 = current target.
zephyr-ref: [ v4.3.0, v4.4.0 ]
# wolfSSL master plus the -stable tag wolfPSA is validated against.
wolfssl-ref: [ master, v5.9.4-stable ]
steps:
- name: Checkout wolfPSA CI driver
uses: actions/checkout@v5
Expand Down Expand Up @@ -59,9 +61,8 @@ jobs:
- name: Build and run wolfPSA samples/tests
working-directory: .github/scripts/zephyr-4.x
run: |
# wolfSSL repo/ref default to upstream wolfSSL/wolfssl master in the
# script.
bash ./zephyr-test.sh \
-r "${{ steps.src.outputs.repo }}" \
-b "${{ steps.src.outputs.ref }}" \
-z "${{ matrix.zephyr-ref }}"
-z "${{ matrix.zephyr-ref }}" \
--wolfssl-ref "${{ matrix.wolfssl-ref }}"
Comment thread
Frauschi marked this conversation as resolved.
115 changes: 106 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Changelog

## Unreleased: PSA Certified Crypto API 1.4 + PQC extension 1.4
## v5.9.4

PSA Certified Crypto API 1.4 + PQC extension 1.4.

Upgrade of the public API surface and implementation to PSA Certified
Crypto API 1.4 Final and the PQC extension 1.4, built against current
wolfSSL master.
Crypto API 1.4 Final and the PQC extension 1.4. This release is validated
against wolfSSL `v5.9.4-stable`: unit tests, TLS client/server, wolfCrypt
benchmark, the Arm PSA Architecture Test Suite and the Zephyr 4.3/4.4
samples run in CI against both that tag and wolfSSL master.

### Breaking changes

Expand Down Expand Up @@ -42,6 +46,50 @@ wolfSSL master.
by neither the effective uid nor root, is refused, and every ancestor is
checked as well (a shared parent such as `/tmp` is accepted when sticky).
Stores that relied on a permissive directory will stop opening.
- wolfSSL >= 5.9.2 is required: the ML-DSA backend moved to `wc_mldsa.c`,
which wolfSSL v5.9.1 does not ship (this release is tested against
v5.9.4-stable). Custom `user_settings.h` files enable ML-DSA with
`WOLFSSL_HAVE_MLDSA`, not `HAVE_DILITHIUM`.
- Overlapping input and output buffers are refused with
`PSA_ERROR_NOT_SUPPORTED` in `psa_cipher_encrypt()`/`psa_cipher_decrypt()`
(every mode with an IV) and in `psa_cipher_update()` for the block modes
(ECB, CBC, CBC-PKCS7). In-place `psa_cipher_update()` still works for the
stream modes (CTR, CFB, OFB, CCM*, ChaCha20).
- Multipart AEAD streams: `psa_aead_update()` returns output as it goes and
`psa_aead_finish()`/`psa_aead_verify()` emit only the tag, per the PSA
contract, instead of buffering the whole payload until finish. Callers must
size the update output buffers accordingly. Additional data supplied after
payload has started is rejected with `PSA_ERROR_BAD_STATE`.
- Auto-assigned key ids come from the vendor range
(`PSA_KEY_ID_VENDOR_MIN`..`PSA_KEY_ID_VENDOR_MAX`) instead of starting at 1,
so they can no longer collide with caller-chosen persistent ids.
- Importing a persistent key under an id already in use fails with
`PSA_ERROR_ALREADY_EXISTS` instead of overwriting the stored key.
- Key lifetimes that name a storage location other than local storage are
rejected instead of being stored locally in plaintext.
- Stricter key policies: key-derivation inputs require
`PSA_KEY_USAGE_DERIVE`; key agreement checks the full policy algorithm, not
only its base; permission checks require every requested usage bit;
`PSA_ALG_ANY_HASH` signature policies are honoured (within one family for
HashML-DSA); `psa_copy_key()` accepts narrowing a wildcard policy to a
concrete algorithm and intersects MAC/AEAD length wildcards.
- `psa_import_key()` checks declared bits against the data length for
byte-string key types (HMAC, RAW_DATA, DERIVE, PASSWORD, PASSWORD_HASH,
PEPPER), and refuses imports whose inferred bits overflow.
- Changed status codes: an empty signature, tag or reference digest reports
`PSA_ERROR_INVALID_SIGNATURE`, as does a wrong-length raw ECDSA signature;
a failed RSA decrypt unpad reports `PSA_ERROR_INVALID_PADDING`; an
unsupported GCM nonce length reports `PSA_ERROR_NOT_SUPPORTED`; store
allocation failures report `PSA_ERROR_INSUFFICIENT_MEMORY`; a store record
that exists but cannot be opened reports `PSA_ERROR_STORAGE_FAILURE`
instead of `PSA_ERROR_INVALID_HANDLE`.
- `NULL` buffers with zero length or zero capacity are accepted across the
API (outputs, nonces, tags, exports, IV generation, encapsulation), and a
zero-byte generation request succeeds.
- Shortened-tag ChaCha20-Poly1305, XChaCha20-Poly1305 and Ascon AEAD
algorithms are rejected at setup. Ed448 PureEdDSA rejects a non-empty
context. TLS 1.2 PSK-to-MS rejects PSKs above
`PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE` (128).

### Added

Expand Down Expand Up @@ -94,17 +142,58 @@ wolfSSL master.
AES-KW, RIPEMD-160, MD5, Ascon and ChaCha20-Poly1305 stay local;
`wolfpsa/psa_engine.h` documents why, plus the X25519 and
`WOLF_CRYPTO_CB_FIND` caveats.
- Fixed: the HMAC path of `psa_mac_*` never called `wc_HmacInit()`, so it
ran with devId 0 and a callback registered on device 0 captured wolfPSA's
HMACs while every other algorithm stayed local.
- Fixed: the one-shot AEAD paths called `wc_AesFree()` on uninitialized heap
when `wc_AesInit()` failed, reading `Aes.devId` and freeing `Aes.streamData`
from unwritten memory. Allocation and init are now one step.
- Optional thread-safe key store: with `WOLFPSA_THREAD_SAFE` a single mutex
built on wolfCrypt's portable `wc_*Mutex` API (created in `psa_crypto_init()`)
guards the volatile-key list and id counter for concurrent PSA callers; a
no-op in single-threaded builds.

### Security

- Side-channel hardening is on in the default build: `WC_NO_HARDEN` was
replaced with `TFM_TIMING_RESISTANT`, `ECC_TIMING_RESISTANT` and
`WC_RSA_BLINDING`, so RSA and ECC private-key operations use the
constant-time paths and RSA blinding.
- `psa_import_key()` rejects a `data_length` that would wrap the internal
buffer size (a heap overflow for key types without an exact-length check).
- ECC keys are pinned to their curve: a public key on import and verify, the
peer point in ECDH, and the exported public key. secp256k1 and Brainpool
are only accepted when `HAVE_ECC_KOBLITZ` / `HAVE_ECC_BRAINPOOL` are set.
- Sensitive intermediate data is zeroized: cipher partial blocks and padded
plaintext on every exit, the CCM init/update/finish stack state, the
computed tag in multipart verify, KDF output on a mid-stream error, and
export buffers on a short key-data read.
- A failed `psa_copy_key()` clears the target id, and the interruptible
max-ops setting is held in an atomic.

### Fixed

- RSA PKCS#1 v1.5 hashed verify compared the recovered DigestInfo with the
raw hash, so every valid signature failed; `hash_length` is now bound to
the algorithm's digest length on sign and verify.
- PBKDF2-AES-CMAC-PRF-128 normalized 16-byte passwords instead of using them
directly (RFC 4615), deriving keys that disagreed with other implementations.
- The CCM counter increment lost its carry for nonces shorter than 13 bytes,
silently corrupting multipart CCM output past the first block.
- The TLS 1.2 PRF KDFs passed the wrong MAC algorithm id to `wc_PRF_TLS()`.
- OFB and CFB decryption keyed AES for the decrypt direction; both modes
run the block cipher forward, so they now use the encrypt key schedule.
- Ed25519ph/Ed448ph sign/verify enforce a 64-byte prehash, and SHAKE256-512
was added to the hash engine so `psa_sign_message()` and
`psa_verify_message()` work for Ed448ph.
- Standalone EdDSA and Montgomery key generation and public-key export work in
builds without `HAVE_ECC`; `psa_export_public_key()` no longer falls through
for disabled PQC backends.
- A second `psa_aead_set_lengths()` call reports `PSA_ERROR_BAD_STATE`;
multipart AEAD length checks and the streaming GCM guards were corrected.
- `psa_hash_compare()` rejects a `NULL` reference hash; generic ECDH reports
NOT_SUPPORTED up front when no RNG is built, instead of failing at the end.
- The HMAC path of `psa_mac_*` never called `wc_HmacInit()`, so it
ran with devId 0 and a callback registered on device 0 captured wolfPSA's
HMACs while every other algorithm stayed local.
- The one-shot AEAD paths called `wc_AesFree()` on uninitialized heap
when `wc_AesInit()` failed, reading `Aes.devId` and freeing `Aes.streamData`
from unwritten memory. Allocation and init are now one step.

### Build configuration

- AES backend policy (`src/psa_config.h`, included by every wolfPSA source):
Expand All @@ -127,6 +216,11 @@ wolfSSL master.
- The multipart AEAD context holds its GCM and CCM `Aes` in a union, since an
operation is one or the other. Under `WC_AES_BITSLICED` that takes
`sizeof(wolfpsa_aead_ctx_t)` from 247,032 bytes to 123,736.
- `make unit-run` builds and runs every unit and regression test, and
`make cov` produces an HTML gcov coverage report for `src/`.
- CI runs the regression suite, a build-configuration matrix with each
feature switched off, and every functional workflow against both wolfSSL
master and `v5.9.4-stable`.

### Zephyr module

Expand All @@ -145,6 +239,9 @@ wolfSSL master.
`psa_its_*`/`psa_ps_*`).
- wolfPSA follows the user's wolfCrypt configuration and exposes exactly the
enabled, wolfPSA-implemented algorithms as the PSA API.
- The module selects the wolfSSL module's constant-time AES backend and ECC
zero-hash allowance by default, and the store returns `MEMORY_E` when an
allocation fails.


## v5.9.1
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ wolfPSA is a PSA Crypto **engine** that implements the PSA Crypto API on

## Build

### wolfSSL version

wolfPSA follows wolfSSL version numbering: wolfPSA v5.9.4 is tested against
Comment thread
Frauschi marked this conversation as resolved.
wolfSSL `v5.9.4-stable`. To build against the matching release:

```
git clone --branch v5.9.4-stable https://github.com/wolfSSL/wolfssl
```

CI also tests against wolfSSL master.

### Building

The build system assumes that wolfSSL is available in a sibling directory under
the same path as this repository, e.g:

Expand Down Expand Up @@ -55,9 +68,9 @@ make wolfPSA WOLFSSL_PATH=~/src/wolfssl

## Testing (PSA Architecture Test Suite)

See `psa-arch-tests/README.md` for instructions on how to run the tests.
See `test-psa-api/README.md` for instructions on how to run the tests.

### Current PSA crypto test results:
### Current PSA crypto test results (wolfSSL v5.9.4-stable):

```
************ Crypto Suite Report ************
Expand Down
2 changes: 1 addition & 1 deletion user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
#define WOLFSSL_LMS_VERIFY_ONLY
#define WOLFSSL_HAVE_XMSS
#define WOLFSSL_XMSS_VERIFY_ONLY
/* Ascon is marked experimental in wolfSSL master and refuses to build
/* Ascon is marked experimental in wolfSSL (5.9.4+) and refuses to build
* without this opt-in. */
#define WOLFSSL_EXPERIMENTAL_SETTINGS
#define HAVE_ASCON
Expand Down
Loading