Web Push (VAPID) key quirks

Issue Description

Web Push (VAPID) key input accepted in Admin UI JMAP Push page , but actions rejected with with cryptic errors.
This could result in impression to admins everything is OK.

  1. Invalid Web Push VAPID key: public key error: ASN.1 error: unexpected ASN.1 DER tag: expected OBJECT IDENTIFIER, got SEQUENCE
  2. Invalid Web Push VAPID key: PKCS#8 ASN.1 error: PEM error: PEM error in pre-encapsulation boundary

I just gave to Claude Code stalwart code and to figure out and to make script for the key.
With the key generated by the script the server started advertising “urn:ietf:params:jmap:webpush-vapid”.

I’m attach the script as reference and his explanation

Setting the Web Push (VAPID) signing key in the admin console (jmap.web_push_key → VapidKey::from_pkcs8_pem) is easy to get wrong — two valid-looking inputs fail with opaque errors that don’t point at the cause.

  1. A valid P-256 key with explicit EC parameters is rejected
    Invalid Web Push VAPID key: public key error: ASN.1 error: unexpected ASN.1 DER tag: expected OBJECT IDENTIFIER, got SEQUENCE
    p256/RustCrypto only accepts the namedCurve OID encoding, but LibreSSL (the default openssl on macOS) — and OpenSSL with explicit-param encoding — emit explicit ECParameters. The key is cryptographically fine; only the parameter encoding differs. Fails:
    openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 # LibreSSL → explicit params
    Works:
    openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve
    Suggestion: accept explicit-parameter P-256 keys (re-encode to namedCurve on load), or make the error say “P-256 key must use named-curve encoding”.

  2. Lightly-mangled paste → “pre-encapsulation boundary”
    Invalid Web Push VAPID key: PKCS#8 ASN.1 error: PEM error: PEM error in pre-encapsulation boundary
    Pasting the PEM into the Secret textarea easily carries a UTF-8 BOM or leading whitespace around -----BEGIN PRIVATE KEY-----, which pem-rfc7468 rejects with this message — hard to spot since the visible text looks correct. Suggestion: strip a leading BOM / trim surrounding whitespace before parsing, or point the error at the offending boundary line.

Stalwart Version

v0.16.x

Installation Method

Binary (macOS)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Confirmed by looking at the source: Stalwart’s Web Push VAPID key parsing (VapidKey::from_pkcs8_pem in crates/common/src/network/webpush.rs) uses the p256/RustCrypto PKCS#8 decoder, which only accepts P-256 keys encoded with namedCurve OID parameters, not the explicit ECParameters form some OpenSSL/LibreSSL builds emit by default. That matches your first error (unexpected ASN.1 DER tag: expected OBJECT IDENTIFIER, got SEQUENCE). The generator function used internally is:

SigningKey::random(&mut OsRng).to_pkcs8_pem(LineEnding::LF)

which always produces a compatible, named-curve PKCS#8 PEM — that’s why Stalwart’s own auto-generated key (created at first startup, see crates/common/src/manager/defaults.rs) works out of the box, while a manually generated key from openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 on macOS’s LibreSSL may not. To generate a compatible key manually, force named-curve encoding:

openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve -out vapid.pem

Your second error is indeed just the PEM parser choking on stray bytes (BOM/whitespace) before the -----BEGIN PRIVATE KEY----- boundary when pasted through the Admin UI textarea — that’s a straightforward PEM-formatting issue on the client side, not a Stalwart-specific setting.

There’s no documented note about the named-curve requirement or PEM-boundary sensitivity in the current docs, so this is a good candidate for a docs/UX improvement (clearer validation error, or trimming/BOM-stripping on input) — a maintainer will likely want to look at that.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

I used the following openssel command and it is valid:

openssl ecparam -genkey -name prime256v1 -noout -out private_key_p256.pem
openssl pkey -in private_key_p256.pem -out private_key_pkcs8.pem

private_key_pkcs8.pem is the valid VAPID key

I also generated valid key with OpenSSL.
The problem is that Admin UI says the key is successfully saved, even if the server cannot use them.
If you do not inspect via JMAP won’t know.

Both failures are the encoding of the pasted key rather than a broken key. The parser wants a PKCS#8 PEM key with named-curve (namedCurve OID) encoding and a clean -----BEGIN PRIVATE KEY----- boundary. The first error is a P-256 key emitted with explicit EC parameters (LibreSSL, the default openssl on macOS, does this); the key is cryptographically fine, only the parameter encoding differs, so re-encoding to named-curve fixes it. The second is a UTF-8 BOM or leading whitespace picked up when pasting into the textarea, which the PEM parser rejects even though the visible text looks correct.

KaKeBr’s two-step works because openssl pkey re-emits the key as PKCS#8 with named-curve encoding:

openssl ecparam -genkey -name prime256v1 -noout -out k.pem

openssl pkey -in k.pem -out vapid_pkcs8.pem

One thing worth knowing: the server generates a valid VAPID key automatically on first startup (on new deployments only), so in most cases you can just use the pre-populated key under the JMAP push settings rather than crafting one.

Update: Fixed in v0.16.15 (yet to be released).

Just to let you know. except this UI issue, everything else seem to work fine. the push notification are signed correctly. i’ll release next week