|
SharkSSL C/C++ Reference
TLS, cryptography, certificates, and PSA integration
|
The sources in this directory implement a documented subset of the PSA Certified Crypto API. The public header is inc/psa/crypto.h: add inc to the include path and include it as <psa/crypto.h>. Build the required src/psa sources as a separate library, and link one PSA provider into the application.
The reported PSA API version identifies the selected interface profile; it does not imply support for every optional algorithm or operation. The sections below describe the implemented operations and their limits.
The default header reports API version 1.5. Define SHARKSSL_PSA_PROFILE_1_4_1=1 when compiling both the provider and its clients to select the common 1.4.1 profile, which reports API major 1 and minor 4. An explicit value of 0 keeps the default 1.5 profile. The profile flag selects the 1.5-only multipart signature types and functions. Hash suspend/resume is available in both profiles. The existing 1.4.1 entry points retain their signatures. Use separate build output directories so objects compiled with different flags cannot be reused accidentally. With GNU Make, the default ODIR=obj-psa writes build/libSharkSSLPSA.a. Selecting a different ODIR writes the archive inside that directory; link the archive from the selected directory to avoid mixing profiles. An explicit PSA_LIBNAME overrides the archive path, including for external build scripts. For MSVC, set the SharkSslPsaProfile141 MSBuild property to 1 and compile the client with SHARKSSL_PSA_PROFILE_1_4_1=1.
The consumer builds separately and can use this provider or an external one. See the consumer build instructions and standalone adapter list.
psa_hash_suspend and psa_hash_resume support every enabled SHA-256, SHA-384 and SHA-512 hash. The state uses the PSA wire format: big-endian algorithm identifier, big-endian total input length (8 bytes for SHA-256, 16 for SHA-384/512), big-endian intermediate state words, then the unprocessed input bytes. The maximum encoded lengths are 107 and 211 bytes respectively. The encoding is independent of the native SharkSSL context layout and the target's endianness. A successful suspend leaves the operation inactive; invalid input to resume leaves an inactive operation unchanged.
psa_sign_setup/psa_verify_setup, optional empty-context calls, incremental updates, finish and abort support the enabled RSA PKCS#1 v1.5, RSA-PSS, randomized ECDSA and deterministic ECDSA hash-and-sign algorithms. The operation hashes streamed message fragments and then uses the existing PSA signature implementation and key policy. Signing requires SIGN_MESSAGE; verification requires VERIFY_MESSAGE. RSA and ECDSA accept only an empty context. Verification setup copies the supplied signature into the operation. Failed setup leaves the operation unchanged. Errors after setup require abort; successful finish and abort release the key dependency and clear the operation. The 1.4.1 profile excludes these operation types and entry points.
psa_wrap_key and psa_unwrap_key support AES-KW (PSA_ALG_KW) and AES-KWP (PSA_ALG_KWP) with an AES-128 or AES-256 wrapping key. KW accepts exportable AES, RAW_DATA, HMAC, DERIVE, PASSWORD, PASSWORD_HASH and PEPPER targets whose length is a multiple of 8 bytes from 16 through 64 bytes. KWP accepts the same types from 1 through 64 bytes. Both modes accept 32-byte ChaCha20 keys when ChaCha20-Poly1305 is enabled. AES targets remain limited to 16 or 32 bytes. X25519, P-256 and P-384 key pairs can be wrapped with either mode. Their public keys can be wrapped with KWP; X25519 public keys also support KW. RSA-2048 and RSA-3072 key pairs and public keys support KWP. Their PKCS#1 DER encoding has a variable length, so the output-size macro gives an upper bound; the actual ciphertext length is computed from the exported DER. RSA wrapping uses a temporary heap buffer that is cleared before release. The wrapping key needs PSA_KEY_USAGE_WRAP or PSA_KEY_USAGE_UNWRAP and a matching algorithm policy; the target needs PSA_KEY_USAGE_EXPORT to be wrapped. KW produces the RFC 3394 default-IV format, 24 to 72 bytes. KWP produces the RFC 5649 padded format, from 16 to 1800 bytes. Unwrapping checks the integrity value, encoded length and zero padding before importing the key with the caller-supplied attributes. A failed integrity check creates no key and returns PSA_ERROR_INVALID_SIGNATURE. The implementation stages key material and ciphertext in private buffers and clears them before returning. PSA_WRAP_KEY_PAIR_MAX_SIZE is 1800 bytes when RSA key pairs are enabled, or 56 bytes when only ECC key pairs are enabled. Opaque driver keys are not supported.
psa_encapsulate and psa_decapsulate support PSA_ALG_ECIES_SEC1 for P-256 key pairs and public keys when SHARKSSL_PSA_HAS_ECIES_P256 is enabled. Encapsulation requires ENCRYPT permission and an exact ECIES policy on the recipient key; decapsulation requires a key pair with DECRYPT permission and the same policy. The 65-byte ciphertext is the ephemeral uncompressed SEC1 public point. Both operations create a 32-byte DERIVE or HMAC key containing the ECDH X coordinate. The caller sets the output key's lifetime, usage and algorithm policy. Encapsulation temporarily occupies a key slot for the ephemeral pair, in addition to the output key slot.
ECIES ciphertext does not authenticate itself. Use the resulting key as input to a KDF, then authenticate the application message. The output cannot be created directly as an AES key in this profile. psa_p256_ecdh.c tests the shared secret against the ciphertext X coordinate with a scalar-one recipient, roundtrip, policy errors and malformed points.
AES-GCM multipart provides encrypt/decrypt setup, optional declared lengths, nonce setting or generation, AAD and payload update, finish/verify and abort. Call psa_aead_set_lengths before nonce setting or generation. Declared lengths are enforced; otherwise GCM accepts incremental input up to the documented implementation caps. AAD must precede any payload update, including a zero-length update. Exact in-place and disjoint payload buffers are supported; partial overlaps are rejected.
AES-CCM uses the same AEAD API. Its multipart form requires psa_aead_set_lengths before nonce setting or generation. It accepts AES-128 or AES-256, nonce lengths 7-13 bytes, and tag lengths 4, 6, 8, 10, 12, 14 or 16 bytes. Generated nonce length is 13, 12 or 11 bytes according to the declared payload length. AAD is limited to 65,535 bytes; payload is limited to UINT32_MAX bytes and must also fit in the CCM length field selected by the nonce. One-shot CCM encryption and decryption stage results privately until completion; one-shot decryption copies plaintext only after tag verification. The PSA CCM engine uses SharkSSL's native AES block primitive and leaves the existing TLS CCM path unchanged.
ChaCha20-Poly1305 uses a 256-bit PSA_KEY_TYPE_CHACHA20 key, a 12-byte nonce and the full 16-byte tag. Shortened tags and 8-byte nonces are not supported. Declared lengths are optional, AAD is limited to 65,535 bytes and payload to UINT32_MAX bytes. Single-part staging additionally requires the payload plus 16 bytes to fit in size_t and available memory. The adapter retains unused native ChaCha block bytes across updates, pads AAD and ciphertext for Poly1305, and authenticates their little-endian 64-bit byte lengths. It reuses the existing AEAD context storage: the public AEAD operation is 608 bytes on x64 and 604 on 32-bit targets because it carries an opaque key-dependency handle. Single-part output is copied only on success, including authenticated decryption; it supports arbitrary input/output overlap.
psa_aead_update emits exactly one byte per input byte; finish and verify emit no residual payload. Encryption finish produces a separate tag of the selected length. Multipart decryption output is tentative until psa_aead_verify succeeds: the application must keep it confidential and discard it on failure. The provider clears its operation secrets on failure but cannot erase buffers returned to the caller by earlier updates. Single-part decryption retains its authenticated-output behavior.
Failed setup leaves the operation unchanged. Errors after setup require abort before reuse. Completion and abort clear the complete operation.
| Area | Supported operations and limits |
|---|---|
| Library and random | psa_crypto_init, psa_generate_random; initialize the RNG before operations that need it. |
| Hash | SHA-256, SHA-384 (SHARKSSL_USE_SHA_384=1) and SHA-512 (SHARKSSL_USE_SHA_512=1), with single-part compute/compare and multipart setup/update/finish/verify, suspend/resume, clone and abort. PSA_HASH_MAX_SIZE is 64 bytes with SHA-512, otherwise 48 with SHA-384 or 32. Single-part input is limited to UINT32_MAX bytes; multipart input is chunked and rejects the algorithm length-counter overflow. Aligned temporary storage permits unaligned output buffers. |
| Key management | SHARKSSL_PSA_KEY_SLOTS live slots (12 in the base configuration, 64 in the Windows provider project); RAW_DATA, HMAC, DERIVE, PASSWORD, PASSWORD_HASH and PEPPER keys of 1-64 bytes, AES-128/256, ChaCha20-256, X25519 key pairs/public keys, and P-256/P-384 key pairs/public keys. P-384 supports ECDH, ECDSA and key-management actions. Import, supported generation, copy, export where permitted, public export, attributes, and destruction are available. psa_attach_key registers driver-provisioned volatile HMAC keys. psa_copy_key retains type and size and intersects usage and algorithm policies; the source needs PSA_KEY_USAGE_COPY, but need not be exportable. ECDSA verification-only copies accept randomized and deterministic policies as equivalent. The destination can be volatile or locally persistent with a registered storage backend. |
| Key wrapping | AES-KW of exportable symmetric keys of 16-64 bytes in multiples of 8 and X25519/P-256/P-384 key pairs; AES-KWP of supported exportable symmetric keys of 1-64 bytes plus ECC and RSA-2048/3072 key pairs and public keys. X25519 public keys also support KW. AES-128/256 wrapping keys. AES targets have 16/32 bytes and ChaCha20 targets have 32 bytes. psa_wrap_key requires target EXPORT and wrapping-key WRAP; psa_unwrap_key requires UNWRAP and imports with the supplied key attributes. |
| Key encapsulation | ECIES SEC1 P-256: ENCRYPT with a public key or key pair, DECRYPT with a key pair. Produces a 65-byte ephemeral SEC1 point and a 32-byte DERIVE or HMAC shared-secret key. The ciphertext is unauthenticated; the application must apply a KDF and message authentication. |
| Key policy query | psa_check_key_usage checks supported operation roles, key type and size, usage flags, and permitted algorithm. PSA_KEY_USAGE_DERIVE_PUBLIC can query the public X25519, P-256 or P-384 ECDH role without private-key policy permission. |
| MAC | HMAC-SHA-256, HMAC-SHA-384 (SHARKSSL_USE_SHA_384=1) and HMAC-SHA-512 (SHARKSSL_USE_SHA_512=1), single-part and multipart. Full 32/48/64-byte MAC or truncation from 4 bytes to the respective digest length; keys remain limited to 1-64 bytes. Minimum-length wildcard policies accept minima from 1 byte to the digest length; actual operations still require at least 4 bytes. Policy copies preserve the larger minimum, including the 64-byte minimum encoded with a zero length field. |
| Key derivation | HKDF, HKDF-Extract and HKDF-Expand with SHA-256, SHA-384 (SHARKSSL_USE_SHA_384=1) and SHA-512 (SHARKSSL_USE_SHA_512=1); PBKDF2-HMAC and TLS 1.2 PRF with the same enabled SHA-256/384/512 hashes. HKDF-Extract requires salt then secret and outputs a 32/48/64-byte PRK; HKDF-Expand requires PRK then info. The full HKDF accepts salt before secret and info before output. PBKDF2 requires integer COST (1 to UINT32_MAX), one or more SALT inputs (concatenated), then PASSWORD. It accepts a direct password or a PASSWORD/DERIVE key and RAW_DATA/PEPPER salt keys. TLS 1.2 PRF takes SEED, SECRET, then LABEL exactly once; seed is limited to 64 bytes and label to 256 bytes. Key inputs require matching algorithm policy and PSA_KEY_USAGE_DERIVE or PSA_KEY_USAGE_VERIFY_DERIVATION. If any input key has only verification permission, verification remains available but byte and key output are denied. psa_key_derivation_verify_key compares against a PASSWORD_HASH key with PSA_KEY_USAGE_VERIFY_DERIVATION, including a non-exportable key. A direct password or secret cannot create an output key. Info and PBKDF2 salt are limited to 256 bytes; these derivations, except SP 800-108 described below, are capped at 255 digest blocks: 8,160/12,240/16,320 bytes with SHA-256/384/512 respectively. Output keys can be RAW_DATA, HMAC, DERIVE, AES or ChaCha20 within supported sizes and policies; PBKDF2 can also output PASSWORD_HASH. The public psa_key_derivation_operation_t block and PRF state each hold 64 bytes. The operation also carries an opaque key-dependency handle; applications and the PSA library must be rebuilt together with matching feature flags, including when SHA-512 is disabled. |
| TLS 1.2 PSK-to-MS | PSA_ALG_TLS12_PSK_TO_MS(hash) supports enabled SHA-256/384/512 and accepts SEED, optional OTHER_SECRET, SECRET (the PSK), then LABEL, each once. Omitting OTHER_SECRET uses zero bytes with the PSK's length. The provider accepts at most 64 bytes for the PSK, seed and other secret, and 256 bytes for the label. It constructs the RFC 4279 premaster secret and streams the selected P_hash output up to 255 digest blocks. DERIVE keys can supply the PSK or other secret; RAW_DATA keys can supply seed or label. A direct PSK allows byte output but cannot create an output key. PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256)) supplies OTHER_SECRET from X25519, P-256 or P-384 ECDH; the enabled SHA-384/512 variants accept the same combined agreement API. |
| AEAD | AES-128/256-GCM single-part and multipart with a 12-byte nonce and 16-byte tag, AAD at most 65,535 bytes and payload at most UINT32_MAX / 8 bytes. AES-128/256-CCM single-part and multipart with nonce 7-13 bytes, supported tags 4-16 bytes as listed above, AAD at most 65,535 bytes and payload at most UINT32_MAX bytes subject to the nonce length. ChaCha20-Poly1305 single-part and multipart with a 256-bit key, 12-byte nonce and 16-byte tag; AAD at most 65,535 bytes and payload at most UINT32_MAX bytes, subject to staging memory limits in single-part calls. |
| Cipher | AES-128/256 ECB and CBC without padding, plus CTR, with single-part and multipart encrypt/decrypt. CBC and CTR use 16-byte IVs; single-part encryption prefixes its generated IV. Multipart updates accept exact in-place buffers when a block mode has no buffered partial block. A partial final ECB/CBC block fails at psa_cipher_finish. |
| Key agreement | X25519/P-256 raw ECDH returns 32 bytes; P-384 returns 48 bytes. P-256/P-384 accept uncompressed 65/97-byte SEC1 peer points, check field range and curve membership, and return the X coordinate. psa_key_agreement can store each result as a volatile or locally persistent DERIVE, RAW_DATA, HMAC or PASSWORD key with the requested usage and algorithm policy. A non-exportable DERIVE result can feed HKDF or TLS 1.2 PRF through psa_key_derivation_input_key. psa_key_derivation_key_agreement feeds ECDH directly to HKDF, HKDF-Extract, HKDF-Expand, TLS 1.2 PRF or TLS 1.2 PSK-to-MS through PSA_ALG_KEY_AGREEMENT, without creating a temporary key handle. |
| RSA public keys | With SHARKSSL_ENABLE_RSA=1: canonical PKCS#1 RSAPublicKey DER import/export, copy, attributes and destroy. Modulus exactly 2048, 3072 or 4096 bits, odd exponent from 3 to UINT32_MAX. Public export needs no EXPORT permission. RSA material is allocated per occupied slot; the configured slot limit remains shared with other keys. |
| RSA key pairs | Canonical PKCS#1 RSAPrivateKey version-zero import/export, independent copy, attributes, destroy, public export and hash signatures. Modulus 2048/3072 bits with the same exponent limits; two balanced, full-width factors only. Import checks arithmetic and CRT consistency; it does not test primality. Private export requires EXPORT permission. With SHARKSSL_ENABLE_RSAKEY_CREATE=1, generation supports 2048/3072-bit keys with e=65537. |
| Asymmetric encryption | RSA-OAEP/SHA-256, SHA-384 and SHA-512 (when enabled), and RSAES-PKCS1-v1_5 with 2048/3072-bit keys. Encryption accepts a public key or key pair; decryption requires a private pair and the native RSA API. PKCS#1 v1.5 accepts 0..245/373-byte messages without salt; OAEP uses the label and limits described below. |
| Signatures | P-256/P-384 ECDSA/SHA-256, SHA-384 and SHA-512 (when enabled) randomized or RFC 6979 deterministic signing and verification of a precomputed 32/48/64-byte hash. The ECDSA signature is raw r \|\| s: 64 bytes for P-256, 96 for P-384. RSA PKCS#1 v1.5/SHA-256, SHA-384 and SHA-512 (when enabled) signing and verification of a precomputed 32/48/64-byte hash use 256/384-byte signatures and require SIGN_HASH/VERIFY_HASH permission respectively. RSA-PSS/SHA-256, SHA-384 and SHA-512 (when enabled) support standard-salt and ANY_SALT hash signatures. RSA-4096 public keys additionally verify 512-byte PKCS#1 v1.5 and PSS signatures. RSA signing requires a private key pair and SHARKSSL_ENABLE_RSA_API=1. ECDSA_ANY and RSA PKCS#1 v1.5 RAW accept arbitrary digest/T bytes through hash APIs only. The supported hash-bound algorithms are available through psa_sign_message/psa_verify_message, which compute the message hash internally and require message permissions. |
psa_generate_key_custom accepts the default production parameters (zero flags and empty custom data) and follows psa_generate_key. For RSA key pairs, it also accepts the explicit little-endian public exponent 65537. Other valid RSA exponents return PSA_ERROR_NOT_SUPPORTED; malformed exponents and custom data for other key types return PSA_ERROR_INVALID_ARGUMENT.
psa_key_derivation_output_key_custom accepts the default production parameters (zero flags and empty custom data) and follows psa_key_derivation_output_key. Other production parameters are rejected; deriving an asymmetric key is not supported by this provider.
The exact RSA, ECC and AES availability depends on the SharkSSL configuration; SHARKSSL_PSA_HAS_* macros in inc/psa/crypto.h describe the selected build. P-256 ECDH currently requires the native private ECC operation and point validation, so SHARKSSL_PSA_HAS_ECDH_P256 follows SHARKSSL_PSA_HAS_ECDSA_P256 and SHARKSSL_PSA_HAS_ECDSA_SIGN. P-384 ECDH requires the native ECC private operation and point validation; their capability is SHARKSSL_PSA_HAS_ECDH_P384. P-384 key management is also available when SHARKSSL_PSA_HAS_ECDSA_P384 enables signature verification without signing. The standalone PSA Makefile and MSVC project enable SHA-512 by default. Use SHARKSSL_USE_SHA_512=0 in the Makefile or SharkSslUseSha512=0 in MSBuild to omit it; direct source builds follow SharkSSL_cfg.h. Compile clients and provider with matching hash and AEAD feature flags. The hash operation layout is unchanged (212 bytes), but PSA_HASH_MAX_SIZE changes and internal message-signature temporaries grow with it; rebuild clients and the library together. SHA-512 hashing, HMAC, HKDF (full, Extract and Expand), PBKDF2-HMAC, PRF/PSK-to-MS, RSA signatures/OAEP and ECDSA are available. The public MAC operation layout carries an opaque key-dependency handle (400 bytes on x64, 396 on 32-bit targets); PSA_MAC_MAX_SIZE is 64 bytes with SHA-512, otherwise 48 with SHA-384 or 32. RSA-OAEP and signatures select the enabled SHA-256/SHA-384/SHA-512 hashes as documented.
The Makefile enables ChaCha20-Poly1305 by default. Set SHARKSSL_USE_CHACHA20=0 there or SharkSslUseChaCha20=0 in MSBuild to omit both ChaCha20 and Poly1305; direct source builds follow SharkSSL_cfg.h. SHA-512 PRF support is the generic P_hash adapter; it does not add a TLS cipher suite to SharkSSL. ECDSA truncates a SHA-512 digest to the curve-order width, while RFC 6979 uses HMAC-SHA-512 for nonce generation.
HMAC multipart update accounts for the initial ipad block and rejects the hash length-counter overflow before reading input. SHA-256 accepts at most 2^61-1 inner-hash bytes; SHA-384/SHA-512 at most 2^125-1. Finish uses aligned digest storage, supports unaligned output, and clears temporary secrets and the operation. Errors after setup require abort. psa_hmac512.c tests RFC 4231 vectors within the supported key limit, independent binary vectors, all splits and truncations, wildcard policies and copies, state/error/erasure paths and synthetic counter boundaries.
The Makefile provider enables P-384 by default and accepts SHARKSSL_ECC_USE_SECP384R1=0 to omit it. An HMAC or AES key with PSA_ALG_NONE can be imported for permitted non-cryptographic actions such as export; it cannot be used for MAC or AEAD.
Optional opaque volatile HMAC keys are supported through the SharkSSL driver extension described below. This profile does not include external persistent keys or read-only persistence, other key derivation algorithms, unlisted signature hashes and curves, XOF and PAKE operations, SHA3/SHAKE, post-quantum algorithms, or other unlisted algorithms. The KEM entry points currently support only ECIES SEC1 P-256. If a future post-quantum implementation needs SHA3 or SHAKE, the shared cryptographic primitives belong in SharkSSL's native crypto core; src/psa should contain only their PSA API adapters. The implementation profile is a functional compatibility claim for the listed API surface; it is not a certification of the complete PSA Crypto API.
The test sources in examples/test/psa exercise this profile. The Arm Architecture Test Suite adapter there selects cases from its Crypto API 1.2.1 release, so those cases alone do not establish 1.4.1 conformance.
PSA_ALG_SP800_108_COUNTER_HMAC(hash) supports SHA-256/384/512 when enabled, using the standard PSA construction and algorithm encoding. Supply SECRET, then optional LABEL, then optional CONTEXT, each at most once. The label must not contain null bytes and is limited to 128 bytes; context is binary and limited to 256 bytes. Omitted label/context are empty. Set capacity before output: its initial value is 0x1fffffff bytes, and the first output request freezes the encoded bit length. The counter is 32 bits, so output is not limited to the 255 blocks used by HKDF. Reading output in chunks does not change the result. Abort releases tracked key dependencies and clears state.
A secret key can be a local DERIVE or HMAC object with the exact algorithm policy and DERIVE or VERIFY_DERIVATION usage. Other key inputs use RAW_DATA. Verification-only input keys cannot produce byte/key outputs. Creating a non-exportable AES output uses psa_key_derivation_output_key; a secret supplied as raw bytes cannot create an output key. Existing key revocation and output policy checks apply. Opaque-driver SP 800-108 dispatch is not implemented by this software provider; it must not export an opaque root as a fallback. The public operation adds two 32-bit fields, so rebuild provider and consumers together. This support does not establish FIPS validation or full PSA conformance.
The construction and input ordering follow the PSA SP 800-108 definition. The separate PBKDF2 extension below remains available to existing callers.
A PSA_KEY_TYPE_PASSWORD or PSA_KEY_TYPE_PEPPER key may use PSA_ALG_PBKDF2_HMAC(PSA_ALG_ANY_HASH) as its permitted algorithm. This is a SharkSSL policy extension, not a standard PSA PBKDF2 wildcard. It permits DERIVE or VERIFY_DERIVATION operations with a concrete supported SHA-256, SHA-384 or SHA-512 PBKDF2 algorithm, subject to the key's usage flags and compiled hash support. Password-hash keys do not accept it.
The wildcard cannot initialize a derivation operation. Applications must select a concrete hash in psa_key_derivation_setup(). A key copy can narrow the wildcard to one hash; copying an exact-hash key with a wildcard request retains the exact hash and never broadens the source policy. Applications using another provider must obtain equivalent policy support explicitly.
Volatile external PASSWORD and PEPPER keys can use the optional SharkSslPSAKeyDriver.pbkdf2_block callback. The provider retains only the driver handle and a revocable key dependency; each PBKDF2 block is computed in the driver with a concrete hash. For an opaque PASSWORD, the driver receives the salt; for an opaque PEPPER, it receives the other password and the salt fragments surrounding the pepper. The root bytes are never copied into the provider. Only one opaque root is supported per derivation. Driver-backed persistent PSA key IDs remain unsupported; a driver may retain provisioned material across restarts and attach it to a new volatile key handle by label. The public derivation operation is now 776 bytes on x64 and 760 bytes on 32-bit targets; rebuild applications and the provider together.
inc/psa/SharkSslPSAStorage.h declares the SharkSSL-specific storage callback interface. Include it as psa/SharkSslPSAStorage.h. It supplements the standard psa/crypto.h; it is not a standard PSA header or a storage format. The provider supports exactly PSA_KEY_LIFETIME_PERSISTENT in local storage, alongside PSA_KEY_LIFETIME_VOLATILE. The persistence/location lifetime macros and psa_purge_key are available in the public PSA header. Other persistence values and external locations are not supported. User persistent IDs must be between PSA_KEY_ID_USER_MIN and PSA_KEY_ID_USER_MAX; volatile handles are allocated separately in the vendor range.
Register a complete SharkSslPSAKeyStorage table with SharkSslPSAKeyStorage_set before creating persistent keys. The table is copied; its context must remain alive. Registration/unregistration requires an empty RAM key store and a quiescent application with no cryptographic operations in progress. Destroy volatile keys and purge persistent caches before changing the table. A backend must continue to own all outstanding IDs. An invalid table returns PSA_ERROR_INVALID_ARGUMENT; occupied slots return PSA_ERROR_BAD_STATE without changing the registered backend.
Callbacks run while the provider holds its key-store lock. They must not reenter PSA or storage registration. The platform backend must serialize external writers and make metadata and material consistent across a query and its subsequent read. The provider queries attributes and length before allocating, bounds the length, compares both reads and validates the complete key encoding using the same checks as import. Missing records become PSA_ERROR_INVALID_HANDLE during key use; malformed records become PSA_ERROR_DATA_CORRUPT where the invalid encoding is detected. Storage, communication and allocation errors propagate to the operation.
Creation is create-only: an existing ID returns PSA_ERROR_ALREADY_EXISTS. The create callback must atomically store attributes and material and make them durable before returning success. Failure must leave no newly created record. Import, supported generation, copy, derivation output and key-agreement output share the import/publish path; a handle is published only after storage success. Copy intersects policy and protects its source slot from eviction.
SHARKSSL_PSA_KEY_SLOTS RAM slots (12 in the base configuration) are shared between volatile keys and persistent caches. The backend may store more keys than the slot count: the provider evicts a persistent cache when it needs a slot, without deleting its durable record. When all slots contain active volatile keys, another record cannot be loaded until a slot is freed.
The Windows SharkSSLPSA.vcxproj simulator build defaults to 64 slots for concurrent TLS use. Its optional MSBuild property SharkSslPsaKeySlots is a positive integer slot count that sets SHARKSSL_PSA_KEY_SLOTS when compiling the provider. Increase it for workloads that need more capacity, for example /p:SharkSslPsaKeySlots=128. This does not change the base embedded configuration or an external hardware provider's limits.
A slot counts a resident key, not a socket. Several keys can remain live per TLS connection, with additional transient demand during handshakes and key updates. Browser connections, outbound clients, session caches, and persistent key caches share the pool. Test their combined peak and leave temporary-key headroom. Dynamic allocation alone does not increase the slot limit.
By default, these slots form a fixed array. Build the SharkSSL PSA provider with SHARKSSL_PSA_DYNAMIC_KEY_SLOTS=1 to allocate stable DoubleList nodes only as keys are needed; SHARKSSL_PSA_KEY_SLOTS remains the maximum number of simultaneously resident slots. A destroyed or purged slot is securely cleared and freed, while eviction clears and reuses its node without moving another slot. The dynamic setting affects this provider, not an external PSA provider selected by the SharkSSL consumer. It adds allocator activity and possible heap fragmentation, so the fixed array remains the embedded default. For more concurrent keys, increase the limit as well as enabling dynamic allocation; enabling it alone does not raise the selected slot capacity.
For example, build the provider in a separate output directory with make -C build PSA_CRYPTO=1 ODIR=output/psa-dynamic XCFLAGS=-DSHARKSSL_PSA_DYNAMIC_KEY_SLOTS=1 all. PSA_KEY_USAGE_CACHE permits retention; without it, persistent material is cleared from the slot at the end of the current locked access. Multipart operations keep opaque key-dependency handles alongside their private key snapshots; the key store retains no pointer to a caller-owned operation and the handles contain no key material. Both inline material and allocated RSA material are cleared when a slot is purged, evicted or destroyed.
psa_purge_key removes a persistent RAM cache and preserves the stored key and any multipart operations using it; it is a successful no-op for a live volatile key. An uncached persistent key is checked without allocating a slot. psa_destroy_key revokes active multipart dependencies before removing the durable record, even when it is uncached or corrupt and no slot is available. The next multipart API call using a revoked dependency returns PSA_ERROR_BAD_STATE and clears that operation's state. A failed backend remove preserves the record for retry according to the callback contract, but does not restore already revoked operations. Destroying the null key succeeds.
No storage adapter is registered automatically. The optional encrypted file adapter is described below; flash adapters remain platform-specific. The backend owns portable serialization and format versioning, integrity, confidentiality, access isolation, power-loss atomicity and secure deletion. Registering callbacks alone does not provide these platform guarantees. The tests use an in-memory backend. Their host write/read modes serialize a same-ABI test fixture across two separate processes and check an independent HMAC result; this is not a production file format or a flash power-loss test.
psa_persistent.c covers registration, lifetimes, collisions, reload, cache/purge behavior, policy and copies, storage failures and corrupt records, slot pressure, supported key encodings, signing and derivation. The GNU-only psa_persistent_fault.c injects allocation and storage-read/create failures and observes RSA heap erasure and live allocations. Build/run it using make PSA_CRYPTO=1 psa-persistent-fault-test; the regular persistent test is included in psa-test, the MSVC runner and the Nucleo firmware.
The public MAC, cipher, AEAD and derivation operation layouts now include opaque dependency handles. Applications and the PSA library must be rebuilt together with matching feature flags. The maintained psa_key_lifetime.c test covers destruction during MAC, cipher, AEAD and derivation, cache purge, persistent-ID reuse, storage failures, multiple KDF inputs, combined ECDH and tracking-allocation failures. Complete PSA conformance remains open.
Include psa/SharkSslPSAFileStorage.h and initialize a SharkSslPSAFileStorage with SHARKSSL_PSA_FILE_STORAGE_INIT. After psa_crypto_init, call SharkSslPSAFileStorage_open with a trusted directory and a separately provisioned 32-byte wrapping key. Check its result, then register &file_store.storage with SharkSslPSAKeyStorage_set. Opening an adapter does not register it. Keep the object alive and do not copy it while open. Unregister at a quiescent point before calling SharkSslPSAFileStorage_close; the close function releases the OS lock and clears the adapter's wrapping-key copy, without deleting stored keys.
Build with make PSA_CRYPTO=1 PSA_FILE_STORAGE=1. The MSVC solution accepts /p:SharkSslPsaFileStorage=true; link applications with bcrypt.lib and advapi32.lib. The adapter is excluded from both libraries by default. make PSA_CRYPTO=1 PSA_FILE_STORAGE=1 psa-file-storage-test runs the regular filesystem and portable-record tests. Bare-metal and configurations without AES-256-GCM return PSA_ERROR_NOT_SUPPORTED; they retain the existing platform storage callback interface and do not acquire filesystem dependencies.
Each version-one record has a 48-byte authenticated header, the encrypted key material, and a 16-byte GCM tag. The header contains nine big-endian 32-bit fields: magic 0x53505341, format version, key ID, lifetime, type, bit count, usage, algorithm and material length; a 12-byte nonce follows. Attributes are visible and authenticated, while key material is encrypted with AES-256-GCM. The material bound is SHARKSSL_PSA_RSA_PRIVATE_MAX_SIZE (1792 bytes). Native GCM is used directly, avoiding PSA reentry inside locked callbacks. Reads, including length queries, authenticate before returning attributes or material. The provider subsequently validates the supported key encoding and policy. No C structure is written to disk.
Linux uses getrandom for nonces, mode-0700 directories, private regular files, descriptor-relative operations and nonblocking flock. Windows uses BCryptGenRandom, UTF-8 path conversion and protected owner-only DACLs. Reparse points/symlinks are rejected. The adapter holds an exclusive store lock until close; other processes must wait or handle PSA_ERROR_BAD_STATE. Inherited contexts are rejected after fork. All writers must cooperate with the lock, and parent directories must remain trusted.
Creation writes and flushes an encrypted staging file, publishes the ID without replacement, and synchronizes the directory on Linux. Windows flushes the record and uses a same-volume MoveFileExW with MOVEFILE_WRITE_THROUGH. Deletion renames the ID to an encrypted tombstone and synchronizes the name change before reporting success. Staging files and tombstones are discarded on reopen. An interruption before acknowledgement can leave either transaction outcome; no partial record is published. Supported filesystem and device flush semantics remain prerequisites for durability. Process interruption tests do not prove physical power-loss behavior. See the platform documentation for fsync, MoveFileExW and FlushFileBuffers.
Recoverable failures roll back creation/deletion. If rollback I/O also fails, the instance refuses further callbacks with PSA_ERROR_STORAGE_FAILURE. Repair storage and reconcile the affected ID before resuming after reopen; the durable result of failed media cannot be inferred from a failed call.
Keep the wrapping key outside the record directory and retain it across restarts. Back up and rotate it using the application's key-management policy. A wrong key makes existing records fail authentication. The adapter neither persists the wrapping key nor enforces its lifetime globally. With random 96-bit IVs, the application must keep total encryption invocations per wrapping key, across all stores and restarts, within the limit in NIST SP 800-38D section 8.3. This adapter does not prevent replay of an older valid record or provide physical secure erasure of filesystem snapshots and device copies.
psa_storage_record.c uses an independent Python cryptography AES-GCM vector, round trips from one byte through the material bound, mutation of every record byte, wrong IDs/keys and output canaries. psa_file_storage.c tests real files, duplicate IDs, reload, authentication failures, exclusive locking, fork ownership and transaction checkpoints. The Linux/GNU-only psa_file_storage_fault.c injects syscall, nonce-generation and plaintext-allocation failures, including rollback failure and refusal by the poisoned instance. Restart runners execute separate processes and terminate at transaction checkpoints. Nucleo exercises the portable record codec, the unsupported filesystem stub and provider callback regression; it has no filesystem backend in this firmware.
SharkSslPSARSA.c must be linked with the other PSA providers. Its capability flag is SHARKSSL_PSA_HAS_RSA_PKCS1V15_VERIFY. The Makefile provider and the MSVC PSA project include it. psa_rsa.c is part of make PSA_CRYPTO=1 psa-test and the Nucleo firmware. psa_rsa_oom.c additionally tests allocation failures and 5,000 bounded DER mutations on hosts with -Wl,--wrap=malloc,--wrap=calloc,--wrap=free. psa_rsa_private.c is included by psa_rsa.c; it is not a separate compilation unit. Its private keys are public test fixtures generated with cryptography/OpenSSL.
Import rejects negative/nonminimal INTEGERs, indefinite/nonminimal lengths, truncation, trailing bytes, even moduli and invalid exponents. SubjectPublicKeyInfo and private-key DER are not accepted as public-key input. The bit attribute is the modulus size; a nonzero supplied value must match. Unsupported modulus sizes/exponents return NOT_SUPPORTED. Generation of a public key is invalid. Public import and verification accept 2048-, 3072- and 4096-bit moduli. Private import, generation, signing and asymmetric encryption remain limited to 2048/3072 bits. PSA_SIGNATURE_MAX_SIZE is 512 bytes for verification; PSA_SIGN_OUTPUT_SIZE still returns zero for a 4096-bit private key.
RSA-4096 support is limited to public-key import/export, copy and signature verification, including certificate-authority signatures. Private import, generation, signing, encryption and wrapping remain limited to 2048/3072 bits. SHARKSSL_PSA_RSA_PUBLIC_MAX_BITS and SHARKSSL_PSA_RSA_PUBLIC_MAX_SIZE bound the public verification path separately from private-key workspaces.
The provider copies only public DER under the existing store lock before verification. Copy owns a separate allocation; destruction clears and frees the material. Failed allocation publishes no new key. Verification rejects a representative greater than or equal to the modulus and checks the complete EMSA-PKCS1-v1_5 encoding, including the SHA-256/SHA-384 DigestInfo and padding. The caller's signature is never modified. Verification uses existing BigInt public modular exponentiation.
Private import accepts canonical PKCS#1 RSAPrivateKey version zero, with all nine INTEGER fields and no trailing data. Both factors must occupy half the modulus width and have their top bit set. Validation checks odd, distinct factors, n = p*q, 1 < d < n, dP = d mod (p-1), dQ = d mod (q-1), d*e = 1 mod (p-1) and mod (q-1), and qInv*q = 1 mod p with qInv < p. The existing native BigInt multiplication and modulo routines perform these checks. No primality test is performed. Import-time validation is variable time and does not establish side-channel resistance.
SHARKSSL_PSA_HAS_RSA_KEY_PAIR indicates this key-storage capability. Export preserves private DER exactly and requires EXPORT permission; psa_export_public_key emits only n and e without that permission. Validation scratch memory and stored private material are cleared before freeing, including allocation-failure paths. Private decryption returns NOT_SUPPORTED. The raw-signature identifier remains defined for source compatibility only. This profile does not claim complete PSA 1.4.1 conformance.
SHARKSSL_PSA_HAS_RSA_PKCS1V15_SIGN requires RSA and the native RSA API. psa_sign_hash supports PKCS#1 v1.5/SHA-256 and SHA-384 (when enabled), PKCS#1 v1.5 RAW, and RSA-PSS as described below. SIGN_HASH permission is sufficient; the key need not be exportable. The public dispatch supports RSA even when ECDSA is disabled. PSA_SIGN_OUTPUT_SIZE returns the modulus byte length for the supported RSA key pairs and algorithm.
The signer snapshots private DER under the store lock, builds aligned native n,p,q,dP,dQ,qInv material and supplies a nonzero public exponent. It refreshes the native RNG from the PSA entropy source before the existing native RSA blinding operation. Every fallible native BigInt operation is checked; allocation errors propagate and native CRT scratch is cleared on every exit. SharkSslBigInt_expmod now clears its allocated intermediates before freeing. Its exponentiation algorithm is unchanged.
Before returning output, the signer checks the signature is below the modulus and applies the public exponent to compare the entire expected PKCS#1 encoded hash. A mismatch returns HARDWARE_FAILURE without releasing the signature. All signing errors leave the caller's signature buffer unchanged and set the reported length to zero when a valid length pointer is supplied. Unaligned output and overlap with the input hash are supported by private staging.
The allocation harness forces all ten signing allocation points individually, including calloc introduced by compiler optimization, and verifies erasure and cleanup. psa_rsa_fault.c tests modified native output, native allocation failure, entropy failure, a zero blinding draw and a native RNG error. Link it against separate provider objects using the wrap options in its header.
The existing native exponentiation is variable time. RNG blinding and the public-result check do not establish complete side-channel or physical-fault resistance. The separate RSA side-channel review remains open; this increment adds functional signing and error handling, not a constant-time implementation.
SHARKSSL_PSA_HAS_RSA_PSS_VERIFY requires RSA; signing also requires SHARKSSL_ENABLE_RSA_API. PSS uses the provider's existing private/public RSA operations and hash API, independently of the native certificate PSS flag SHARKSSL_ENABLE_RSASSA_PSS.
PSA_ALG_RSA_PSS and PSA_ALG_RSA_PSS_ANY_SALT support SHA-256 and the enabled SHA-384/SHA-512 hashes. Verification accepts 4096-bit public keys; private operations retain the 2048/3072-bit restriction. The hash input must be exactly 32/48/64 bytes for SHA-256/384/512. MGF1 uses the same hash. Signing uses a random salt of one digest length for both variants; verification requires that length for the standard variant, and accepts 0 through modulus_bytes - hash_bytes - 2 bytes for ANY_SALT. Both signatures occupy exactly the modulus byte length.
Verification checks the representative range, trailer, unused high bit, zero padding, delimiter, salt length and salted digest. It never modifies the caller's signature. Signing obtains the salt through psa_generate_random and retains native blinding, private staging, public-result verification and cleanup. RNG/hash/allocation failures propagate; signing errors release no output and report zero signature length. No new side-channel claim is made.
Algorithm policy matching keeps standard-salt and ANY_SALT distinct, including when signing. PSA_ALG_ANY_HASH is accepted in either PSS policy, permits only supported hashes within that same PSS variant, and cannot be used as an operation algorithm. Copying intersects a wildcard with a concrete policy; copying between the two PSS variants fails. ECDSA and PKCS#1 v1.5 also support ANY_HASH policies as described below.
psa_rsa_pss.c, included by psa_rsa.c, has 52 independent OpenSSL-backed vectors, including malformed encodings and isolated high-bit violations below the modulus. The contract suite has 376 PSS checks when SHA-384 is enabled. The host allocation and fault harnesses also cover PSS, including salt RNG, salted-hash/MGF1 failures and a corrupted private operation. The optional test define PSA_RSA_SKIP_SLOW_GENERATION omits only the two random key construction tests; the key-generation argument/policy checks remain active.
The ELF archive build localizes hidden native symbols, then restores the GCC x86 PIC helper symbols to global binding: those symbols name COMDAT sections and localizing them breaks links with ordinary 32-bit PIE callers.
SHARKSSL_PSA_HAS_RSA_KEY_GENERATION requires RSA, its native RSA API and SHARKSSL_ENABLE_RSAKEY_CREATE=1. The PSA Makefile, MSVC project and Nucleo test builds enable this option; custom builds and consumers must use matching configuration. psa_generate_key accepts volatile or locally persistent RSA pairs with exactly 2048 or 3072 bits and the existing RSA policies. Zero bits are invalid; other sizes are unsupported. The public exponent is 65537.
The native generator uses small-prime division and 64 Miller-Rabin rounds with rejection-sampled witnesses in [2, n-2]. Squaring updates the witness state on every step. RNG and allocation errors propagate instead of being treated as composite candidates. Retries are bounded at 128 witness draws, 65,536 prime candidates and 128 factor pairs; exhausted retries report INSUFFICIENT_ENTROPY. These implementation limits are not PSA requirements. Native generation accepts aligned lengths from 128 through 4096 bits; the PSA interface exposes only the two sizes above.
The adapter recomputes d, which the native key format omits, and emits all nine PKCS#1 INTEGER fields. The existing private import validator checks arithmetic and CRT consistency before allocating a key handle. Errors leave the output handle null. Scratch buffers and native key material are cleared before release. Prime generation, GCD and inversion remain variable-time; this increment does not establish side-channel resistance or certification.
psa_rsa_generate.c, included by psa_rsa.c, tests both sizes, policy, export/reimport, public export and signatures. psa_rsa_generate_fault.c uses public fixture factors to isolate all 16 construction/import allocation points, verify erasure and test RNG failure and repeated equal factors. psa_rsa_prime.c includes the native implementation to test private helpers with 8/16/32-bit words, primes and composites, all 243 allocation points in its witness sequence, RNG failures and exhausted candidate retries. Its deterministic RNG is confined to that host test. Both fault harnesses run normally and with ASan/UBSan. Independently exported test keys and signatures are checked with OpenSSL; they are not retained as production credentials.
psa_asymmetric_encrypt and psa_asymmetric_decrypt support PSA_ALG_RSA_OAEP with enabled SHA-256/SHA-384/SHA-512 and 2048/3072-bit RSA keys. The same hash is used for the label and MGF1. The optional salt argument is the OAEP label (including embedded zero bytes); it is not the random seed. The native OAEP feature flag is not required. Encryption requires RSA; decryption also requires SHARKSSL_ENABLE_RSA_API=1.
Encryption accepts public keys or key pairs with ENCRYPT permission; decryption requires a key pair with DECRYPT permission. The algorithm policy must match exactly. OAEP ANY_HASH policies and other hashes are unsupported. Import, copy and key-usage queries use the same permissions and algorithms.
Ciphertext is exactly modulusBytes bytes. The maximum plaintext length is modulusBytes - 2*hashBytes - 2: 190/158/126 bytes for 2048-bit SHA-256/384/512, and 318/286/254 bytes for 3072-bit SHA-256/384/512. Empty messages are supported. The output-size macros reflect these bounds. Buffers may overlap. Lengths are set to zero on failure and caller output is not written until success. Invalid ciphertext lengths report INVALID_ARGUMENT; out-of-range RSA representatives, a wrong label or malformed OAEP report INVALID_PADDING.
OAEP uses the existing PSA hash/RNG API and a bounded MGF1 workspace. Private RSA retains native blinding and public-result verification. The decoder scans the full padding span before reporting failure; this reduces padding-oracle timing leakage but is not a complete side-channel guarantee. Native private exponentiation remains variable-time. Sensitive scratch, including the public check's plaintext representative, is cleared. Native BigInt code is unchanged.
psa_rsa_oaep.c contains 32 independent ciphertext vectors for both hashes and key sizes: empty, normal and maximum-length messages, and malformed label hash, zero padding, delimiter and leading octet. Its 300 contract checks also cover long binary labels, overlap, buffer sizes, key type, policies and invalid arguments. The host fault/allocation harnesses cover OAEP entropy, hash and private-result failures and every allocation point (one encrypt, ten decrypt), including output preservation and private-workspace erasure.
psa_sign_message and psa_verify_message hash the input using the selected signature algorithm, then invoke the existing RSA/ECDSA provider with SIGN_MESSAGE/VERIFY_MESSAGE permission. They never require SIGN_HASH or VERIFY_HASH. Hash permissions imply the corresponding message permissions when attributes are normalized; message permissions do not imply hash usage.
Supported algorithms match the current hash signature paths: RSA PKCS#1 v1.5 with enabled SHA-256/384/512; RSA-PSS and ANY_SALT with the same hashes; randomized/deterministic ECDSA P-256/P-384 with SHA-256/384/512 signing and verification. The existing PSS ANY_HASH policy permits concrete message algorithms within its same salt variant. Wildcard operation algorithms and raw signature algorithms are invalid. PSA_ALG_IS_SIGN_MESSAGE identifies the supported hash-and-sign categories.
Empty messages (NULL, zero length), binary input and overlapping input and signature output are supported. Pointer/length pairs are checked; signing sets the returned length to zero on error and preserves the output buffer. Verification does not modify the message or signature. A bounded PSA_HASH_MAX_SIZE-byte hash temporary is cleared on every return after hashing. Native blinding, private-result checks and existing side-channel limitations are preserved.
psa_message.c, included by the host/Nucleo RSA suite, adds 442 checks with all algorithms enabled. Seven independent cryptography/OpenSSL signatures cover PKCS#1 v1.5 and PSS for both RSA sizes and ECDSA P-256. Both PSS salt variants use the PSS vectors. Contracts cover message-only permissions, public/pair roles, denied usage, deterministic verification equivalence, empty/binary inputs, overlap, buffers, changed messages/signatures and invalid arguments. Message signing allocation/RNG/hash/native faults and PSS wildcard policy checks are also exercised by the host fault/OOM harnesses.
The four psa_sign_message_with_context, psa_verify_message_with_context, psa_sign_hash_with_context and psa_verify_hash_with_context functions are available in both the 1.4.1 and 1.5 profiles. For every supported RSA/ECDSA algorithm, the context must be empty: a zero length accepts either NULL or a non-NULL pointer and delegates to the corresponding existing API. This preserves its key permissions, algorithm policy, signature representation, validation and native error handling. A nonzero context length returns INVALID_ARGUMENT before context access, hashing, entropy or private operations. No context bytes are appended to the message or digest.
PSA_ALG_SIGN_SUPPORTS_CONTEXT returns zero for this provider's supported algorithms, including their wildcard policies. The functions accept empty contexts; algorithms with a cryptographic nonempty-context parameter, such as EdDSA variants, remain unsupported. No new native signature algorithm is introduced. Signing requires a length pointer, sets it to zero on failure and preserves caller output when rejecting a context.
psa_message.c adds 827 context checks across the eleven enabled algorithm and key-size rows. Independent signatures, interoperability with the APIs without context, public and private roles, message-only permissions, denied usage, altered signatures, buffer sizes and context lengths 1, 255, 256 and SIZE_MAX are covered. The fault harness verifies delegated failures and rejection before native/hash work. Existing side-channel limitations remain.
PSA_ALG_DETERMINISTIC_ECDSA with enabled SHA-256/384/512 supports P-256 key pairs through hash and message signing, including the empty-context wrappers. RFC 6979 section 3.2 uses the selected HMAC hash and reduces the leftmost 256 digest bits with bits2octets. Nonce candidates are accepted only in the range 1 to n-1; rejected candidates and zero signature components advance the same local RFC state. The result is the exact 64-byte r || s signature, without low-S normalization. The state, private snapshot and temporary signature are cleared on all exits. No temporary PSA key slot is needed for HMAC.
Signing policy distinguishes randomized and deterministic ECDSA. Their verification policies remain equivalent. SIGN_HASH implies SIGN_MESSAGE as required by the PSA usage contract. Unsupported hashes and curves continue to return NOT_SUPPORTED.
The internal native SharkSslECDSAParam_ECDSAEx entry point receives an operation-local nonce callback; the existing native entry point retains randomized behavior and the parameter structure is unchanged. Random side-channel blinding remains enabled and uses the native RNG separately. Consequently this implementation still requires working entropy for blinding, even though the signature nonce is deterministic. The existing side-channel review remains open; these changes add no certification claim.
The versioned MSVC project marks its native objects with SHARKSSL_PSA_PROVIDER_PRIVATE=1. It omits the native certificate-format SharkSslRSAKey_getPublic convenience API, which is not a PSA operation, and prefixes both ECDSA entry points to coexist with the TLS consumer. Normal native SharkSSL builds retain their public API. The maintained Test-SharkSSLPSA.ps1 now includes the RSA/signature suite; its optional -SkipSlowGeneration omits only the two expensive RSA generation cases.
psa_ecdsa_deterministic.c supplies 17 independently verified vectors and 555 host/embedded contract checks. psa_ecdsa_deterministic_fault.c is a host-only harness for HMAC/allocation/entropy/blinding failures, bounded candidate rejection, native retries and secret clearing. It compiles the maintained ECDSA provider into its translation unit and must exclude the separate provider ECDSA object when linked with wrapped native symbols.
PKCS#1 v1.5 supports SHA-256 and enabled SHA-384/SHA-512. The hash/message signature APIs and their empty-context wrappers share the existing native RSA path, blinding and public-result check. Canonical DigestInfo includes the SHA-384 OID and explicit NULL parameters; verification compares the full encoded block, including padding and DER.
Exact SHA-384 and ANY_HASH key policies are accepted, including copies with policy intersection. PSA_SIGN_OUTPUT_SIZE uses the shared concrete algorithm predicate. SHA-384 operations and key imports return NOT_SUPPORTED when SHA-384 is disabled. RAW signatures have their own contract below; SHA-512 uses its own DigestInfo OID and the same signing/verification path.
psa_rsa_pkcs384.c adds independent OpenSSL signatures for public test keys of 2048/3072 bits and 18 malformed EMSA blocks. The contract covers hash/message/context APIs, overlapping buffers, permissions, exact/wildcard copies, digest and signature lengths, output preservation and the disabled SHA-384 profile. The host fault harness also exercises native RSA, entropy, blinding and message-hash failures. This adds no side-channel claim.
With SHARKSSL_USE_SHA_384=1, randomized and deterministic ECDSA accept a 48-byte SHA-384 hash. Native P-256 ECDSA uses its leftmost 256 bits; the raw signature remains 64-byte r \|\| s. The RFC 6979 state uses 48-byte K/V and HMAC-SHA-384, with bits2octets and nonce truncation to 256 bits. Blinding continues to obtain independent randomness from the native RNG.
Exact hash policies keep SHA-256 and SHA-384 distinct. ANY_HASH policies permit either configured hash; randomized and deterministic signing remain distinct, while verification accepts either scheme for the same hash. Hash/message APIs and empty-context wrappers support both hashes. A build without SHA-384 rejects the concrete SHA-384 algorithm and its key policy. psa_ecdsa384.c exercises RFC 6979 vectors, order-boundary digests, public and private keys, copy/query policies, length/buffer/context errors and overlapping hash/output. The fault harness exercises both HMAC hashes. This increment does not add curves or a new side-channel resistance claim.
P-384 private keys are exactly 48-byte big-endian scalars in 1..n-1; public keys are exactly 97-byte uncompressed SEC1 points. Import infers 384 bits when the requested size is zero and rejects inconsistent sizes, zero/out-of-range scalars, compressed/infinity/off-curve points and field coordinates outside 0..p-1. Generation retains the bounded 128-attempt rejection sampler and propagates entropy failures. Public export needs no private EXPORT permission; private export and copies retain their existing permission rules. The inline key storage grows from 65 to 97 bytes per slot.
Raw ECDH returns the full 48-byte X coordinate, including leading zeroes. The public API checks the output capacity against the selected key, so P-256 and X25519 still accept 32-byte outputs. The private agreement helper returns the actual output length to raw agreement and combined derivation; HKDF, TLS 1.2 PRF and PSK-to-MS consume exactly 32 or 48 bytes. The temporary scalar, coordinates and shared-secret buffers are cleared.
P-384 accepts NONE, ECDH, supported combined ECDH/KDF and supported ECDSA policies. Signing and verification permissions follow the selected curve and native API configuration. This extension uses the existing native ECC implementation and timing-resistance settings; the side-channel review remains open.
psa_p384_ecdh.c runs independent OpenSSL and finite-field arithmetic vectors, boundary inputs, buffer/policy/key-copy tests and HKDF/PRF vectors. It is included in the Makefile, MSVC test runner and Nucleo firmware. make PSA_CRYPTO=1 psa-p384-fault-test exercises every observed allocation site in import, public export and agreement, entropy errors, exhausted scalar rejection and rejection followed by a valid scalar. It uses GNU ld wrappers and separate provider objects; it is also run with ASan/UBSan.
PSA_ALG_ECDSA_ANY supports randomized signing and verification on enabled P-256/P-384 curves through the hash APIs, including their empty-context variants. The digest is left-padded with zeros or truncated on the right to the curve width. Empty digests represent zero; a null pointer is accepted only with zero length. The bounded adapter accepts lengths beyond UINT16_MAX without narrowing the caller's length before truncation.
The key's permitted algorithm must be exactly PSA_ALG_ECDSA_ANY. Hash-bound and ECDSA(ANY_HASH) policies do not authorize this operation; copying a key cannot cross that policy boundary. Message APIs reject this identifier with PSA_ERROR_INVALID_ARGUMENT. Nonempty contexts are rejected. Randomized signing uses the existing uniform nonce sampler and native blinding. The normalized digest and private scratch are erased on return.
examples/test/psa/psa_ecdsa_any.c contains independent fixed-nonce signatures and tests lengths 0 through 80 plus 65535, 65536 and 65537 bytes, policy, copy, generation, context and output-error contracts. It is included in make psa-test, the MSVC runner and the Nucleo firmware.
The GNU ld fault harness adds 125 ECDSA_ANY checks to the existing 243 P-384/RFC6979 checks. It fails each observed allocation site in signing and public/private verification, checks secret erasure, and tests entropy/blinding errors, zero/order nonce rejection and retry exhaustion with untouched output.
ECDSA P-384 supports SHA-256 and enabled SHA-384/SHA-512 through randomized and deterministic RFC 6979 signing and verification. Hash, message and empty-context APIs share the selected curve and raw big-endian r || s encoding: 48 bytes per component, 96 bytes total. Public keys can verify without a private key or private signing API. The ECDSA and ECDH capability gates remain separate; disabling P-256 does not enable its ECDH path.
RFC 6979 bits2octets pads SHA-256 on the left for the 384-bit order; the candidate concatenates two HMAC-SHA-256 V blocks and keeps their first 48 bytes. SHA-384/SHA-512 use one block. P-256 retains its leftmost-256-bit digest truncation. Each retry uses the complete last V block, performs step h.3, and rejects zero or candidates at/above the selected order without reduction. The existing fixed-loop order subtraction is shared for 32/48-byte values as part of side-channel resistance; its prior verification remains open. Temporary candidate, reduced digest, seed, private key and signature buffers are cleared. Fortuna refresh and native randomized blinding are preserved.
Randomized P-256/P-384 signing also uses the nonce callback. It draws full-width candidates through psa_generate_random and rejects zero or values at/above the order, with a maximum of 64 attempts. This bypasses the native random path's forced nonce bit and modulo reduction while retaining its separate blinding. Fault tests cover both widths and accept k = 1 unchanged after rejecting zero or the order.
Policy rules retain exact hashes, ANY_HASH restriction and randomized versus deterministic signing distinctions. Verification accepts equivalent schemes. SIGN_HASH/VERIFY_HASH imply their message permissions, as before. Public signing requests, unsupported hashes/curves, wrong digest/component sizes, zero/out-of-range signature components and nonempty contexts are rejected. On signing failure the output is untouched and the returned length is zero.
psa_p384_ecdsa.c has 568 default-profile contract checks, 11 deterministic vectors (four RFC 6979 A.2.6 sample/test vectors and seven boundary digests), randomized SHA-256/SHA-384, private/public verification, message/context APIs, buffer canaries, copy restrictions, key generation and malformed signatures. Expected bytes are independently checked with HMAC, finite-field arithmetic and OpenSSL. The maintained Makefile, MSVC runner and Nucleo execute it.
make PSA_CRYPTO=1 psa-p384-ecdsa-fault-test compiles the provider inclusion with individual native/provider objects and GNU ld wrappers. It exercises all observed signing and public/private verification allocation sites, HMAC failures in initialization, both candidate blocks and retry updates, zero/order nonce rejection, exhausted retries, entropy and blinding failures. The 243 checks pass normally and with ASan/UBSan; the P-256 deterministic fault harness remains a separate 124-check regression.
PSA_ALG_RSA_PKCS1V15_SIGN_RAW signs or verifies the caller-supplied T byte string without hashing or adding a DER DigestInfo. With 2048/3072-bit keys, T may contain 0..245/373 bytes respectively; the signature occupies the full 256/384-byte modulus. The encoding is 00 01 FF...FF 00 T, with at least eight padding bytes. Verification checks the entire encoded block. Lengths are validated as size_t before narrowing to the native width. A null input pointer is accepted only for zero length.
Hash APIs and their empty-context variants accept RAW. Message APIs and nonempty contexts reject it with PSA_ERROR_INVALID_ARGUMENT. Exact RAW and PKCS#1 v1.5 ANY_HASH key policies permit it; exact hash-bound policies do not. Key copies intersect these permissions. SIGN_HASH/VERIFY_HASH usage is required, and signing requires a private key and the native RSA API.
Private staging permits unaligned and in-place buffers. Existing RNG refresh, native blinding, public re-verification of the CRT result, and full workspace erasure are retained. Signing errors leave output untouched and set its returned length to zero. This increment adds no native side-channel hardening; the existing native side-channel review and possible refactoring remain open.
examples/test/psa/psa_rsa_raw.c is included in the maintained RSA suite, MSVC runner and Nucleo firmware. It performs 189 default-profile checks, including nine independent fixed signatures checked with OpenSSL, eight signed malformed encodings, empty and maximum-length T, a 256-byte T, policy/copy/context restrictions, buffer canaries and failure contracts. The public-only RSA_API=0 profile executes 115 checks.
make PSA_CRYPTO=1 psa-rsa-raw-fault-test uses individual provider objects and GNU ld wrappers for malloc/calloc, free, entropy, native RNG, clearing and private RSA. Both normal and ASan/UBSan runs pass 162 checks: every observed signing/public-verification allocation site, entropy and blinding failures, changed CRT output, unchanged caller output, released allocations, and erasure of the complete outer signing workspace. Intercepting calloc also covers GCC's folded allocation plus zero initialization.
PSA_ALG_RSA_PKCS1V15_CRYPT supports RSAES-PKCS1-v1_5 encryption with a public key or key pair, and decryption with a private key pair. The exact algorithm policy and ENCRYPT/DECRYPT usage are required. OAEP, signature and ANY_HASH policies do not authorize this algorithm; copies intersect policy and usage. Encryption remains available when the private RSA API is disabled. The capability flags are SHARKSSL_PSA_HAS_RSA_PKCS1V15_ENCRYPT/DECRYPT; the generic asymmetric flags and output-size macros cover both OAEP and PKCS#1 v1.5.
For 2048/3072-bit moduli, messages may contain 0..245/373 bytes, and ciphertexts occupy exactly 256/384 bytes. Nonempty salt is rejected. The encryptor stages 00 02 PS 00 M, with at least eight independently sampled nonzero padding bytes. Zeros are resampled without substitution or reduction; each byte has at most 64 retries before reporting insufficient entropy. Caller lengths are checked as size_t before narrowing to U16.
Decryption reuses the OAEP private workspace, PSA RNG refresh, native RSA blinding and public re-verification of the CRT result. Its padding helper scans the whole block with unsigned masks before reporting any padding error. This provides padding side-channel resistance; overall native and compiler side-channel review remains open. No native BigInt/RSA code was changed. Every failure leaves caller output untouched and returns zero length; complete private workspace erasure is retained. Unaligned and in-place input/output are supported. An empty plaintext can be returned through a null output pointer with zero capacity.
psa_rsa_crypt.c adds 228 maintained contract checks (98 with RSA_API=0). Its 30 independent integer-RSA vectors cover eight valid plaintexts and 22 malformed encodings: bad first/type byte, no delimiter and every first delimiter position yielding fewer than eight padding bytes. OpenSSL independently confirms all 30 recovered blocks and eight plaintexts. The file is included in the RSA suite, MSVC runner and Nucleo firmware.
make PSA_CRYPTO=1 psa-rsa-crypt-fault-test links separate provider objects with GNU ld wrappers. Its 188 checks pass normally and with ASan/UBSan: all observed encryption/private-decryption allocations, entropy/blinding errors, corrupted CRT output, complete private workspace erasure, allocation release, untouched output/zero length, zero-byte rejection and retry exhaustion. The malloc and calloc wrappers include GCC's folded zero-initialized allocation.
psa_asym512.c covers RSA-2048/3072 PKCS#1 v1.5, PSS (standard and ANY_SALT), OAEP and randomized/deterministic ECDSA P-256/P-384 with SHA-512. Independent OpenSSL fixtures check signatures, maximum OAEP messages and RFC 6979 output. OAEP-SHA-512 accepts at most 126/254 plaintext bytes for 2048/3072-bit keys. psa_kdf_hashes.c covers SHA-384/512 PBKDF2-HMAC, PRF, PSK-to-MS, key input and output, verification-only permissions and X25519 combined derivation. psa_chacha.c covers independent binary AEAD vectors, all payload splits, unaligned and overlapping buffers, altered ciphertext/tag/AAD/nonce/key, policy, state and synthetic length limits. The shared fixtures are in psa_extended_vectors.h.
The standalone Makefile and MSVC test runner include the three new tests. make PSA_CRYPTO=1 psa-extended-fault-test runs the GNU ld host-only wrappers in psa_extended_fault.c: allocation failures, SHA-512 hash/HMAC failures, entropy failures and output preservation. Use sanitizer flags in both compile and link options when running this target with ASan/UBSan.
Include psa/SharkSslPSADriver.h and register a SharkSslPSAKeyDriver callback table with SharkSslPSAKeyDriver_set at a quiescent point. Up to four primary secure-element or vendor-defined locations can be registered. A live RAM key or active dependency prevents registration changes. Tables are copied, while their contexts must remain alive until unregistered. Callbacks execute under the provider key-store mutex and must not call PSA or registration functions.
This first driver profile accepts only volatile HMAC keys, with the existing 1-to-64-byte key bounds and enabled SHA-256/384/512 algorithms. Select an external volatile lifetime using PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION. psa_import_key passes the standard bytes to the driver once and retains only attributes and a nonzero opaque handle. psa_generate_key invokes driver-owned generation without producing secret bytes in the provider. Driver generation must use its own production entropy source. Imported caller buffers remain the caller's responsibility. The driver owns secret protection and erasure; registering an external location alone does not establish hardware isolation.
Single-part psa_mac_compute and psa_mac_verify enforce the normal usage and algorithm policy, including supported truncation and wildcard-policy limits, before dispatch. MAC output is staged and is published only after successful completion with exactly the expected length. Callback failures propagate; an inconsistent output length reports PSA_ERROR_CORRUPTION_DETECTED. Verification compares the returned MAC without an early exit on byte values.
Multipart psa_mac_sign_setup and psa_mac_verify_setup dispatch to the optional driver callbacks when the complete callback group is registered. Each active PSA operation owns one driver operation handle and keeps its key dependency until finish, error or abort. A successful finish consumes that handle; a failed update or finish aborts it. A failed abort still consumes the handle according to the driver contract. The provider stages a signed MAC and publishes it only when the driver returns the expected length. Destroying the key revokes an active operation; its next call returns PSA_ERROR_BAD_STATE.
psa_copy_key can copy an opaque volatile HMAC key within the same driver location when that driver supplies copy_key and the source has COPY usage. The provider intersects usage and algorithm policy before the callback. The driver returns a distinct, independently destructible handle; key bytes never enter the provider. A missing callback or a different target location returns PSA_ERROR_NOT_SUPPORTED. Transfers between local and opaque keys remain unsupported. Rebuild driver modules with this header because the callback table has grown; initialize the entire table to zero before assigning callbacks.
psa_attach_key registers driver-provisioned HMAC material by label with a volatile PSA identifier. The application supplies the external location, HMAC type, byte-aligned size, usage flags and algorithm; the driver checks that these match the key it has provisioned. The provider retains only attributes and a driver handle. An unknown label returns PSA_ERROR_DOES_NOT_EXIST; a persistent lifetime is rejected as PSA_ERROR_INVALID_ARGUMENT. psa_destroy_key calls the driver's destroy_key callback for an attached ID. The driver releases that handle while preserving the provisioned material; imported or generated keys are erased by the same callback. A later attach of the same label receives a new ID. A failed release disables use until an explicit destroy retry succeeds. A driver may offer attachment without import or generation, but must provide destroy_key.
psa_get_key_attributes, psa_check_key_usage, volatile purge and explicit destruction retain their standard roles. A failed driver destruction disables further use but preserves the handle for a later explicit psa_destroy_key retry; successful destruction releases the slot. Drivers must support this retry contract. Persistent external keys and key export are not implemented by this profile and return PSA_ERROR_NOT_SUPPORTED where permitted by the key policy. No external key silently falls back to software using empty or placeholder material. The standard public operation ABI is unchanged by this extension.
psa_opaque_hmac.c uses a driver fixture with published RFC 4231 test-case-1 answers and private fixture storage. The fixture supports those known inputs only; it tests dispatch, handle ownership, registration, policies, truncation, multipart state and abort, error output, destruction retry, attachment and slot exhaustion. It does not implement a production engine or establish secure-element resistance. The same fixture runs on hosts, Carambola and the dedicated Nucleo firmware.
Software-provider RAW_DATA and DERIVE keys accept policies for supported ECDH/HKDF (full, Extract or Expand), ECDH/TLS12_PRF and ECDH/TLS12_PSK_TO_MS chains. Enabled SHA-256/384/512 hashes retain their existing feature guards. This includes non-exportable RAW_DATA salts created by derivation output.
psa_key_derivation_input_key checks the complete combined algorithm when the operation was set up with one. An exact combined policy cannot be used with standalone derivation, a different KDF mode, or a different hash. For compatibility with the existing TLS consumer, auxiliary RAW_DATA/DERIVE inputs may also carry the matching KDF-only policy. This compatibility rule does not apply to an ECDH private key or to psa_copy_key policy intersection. psa_check_key_usage uses the same rule for auxiliary derivation roles.
DERIVE or VERIFY_DERIVATION permission is still required. Verification-only inputs prohibit output; destroying an input key revokes its active operations. The ECDH secret must still be supplied through key agreement, except for the independent PSK input in ECDH/TLS12_PSK_TO_MS. No public operation ABI or key-store slot-count changes are required.
psa_combined_policy.c covers these policies, output_key salts, copying, permission failures, algorithm mismatches and key revocation. It compares policy dispatch with the existing byte-input KDF path; cryptographic known answers are covered separately by the maintained KDF and ECDH suites.