quarkusio/quarkus · error · IllegalArgumentException

Invalid public key

Error message

Invalid public key

What it means

During fromRequiredPersistedData, the stored X.509-encoded public key cannot be rebuilt: KeyFactory.generatePublic throws InvalidKeySpecException (corrupted/wrong-format key bytes or key does not match the algorithm) or NoSuchAlgorithmException (required KeyFactory, e.g. 'EdDSA', is unavailable). It is rethrown as IllegalArgumentException('Invalid public key').

Source

Thrown at extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnCredentialRecord.java:140

                case EC2:
                    coseKey = EC2COSEKey.create((ECPublicKey) KeyFactory.getInstance("EC").generatePublic(x509EncodedKeySpec),
                            coseAlgorithm);
                    break;
                case OKP:
                    coseKey = EdDSACOSEKey
                            .create((EdECPublicKey) KeyFactory.getInstance("EdDSA").generatePublic(x509EncodedKeySpec),
                                    coseAlgorithm);
                    break;
                case RSA:
                    coseKey = RSACOSEKey
                            .create((RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec),
                                    coseAlgorithm);
                    break;
                default:
                    throw new IllegalArgumentException("Invalid cose algorithm: " + coseAlgorithm);
            }
        } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Invalid public key", e);
        }
        byte[] credentialId = base64UrlDecode(persistedData.credentialId());
        AAGUID aaguid = new AAGUID(persistedData.aaguid());
        AttestedCredentialData attestedCredentialData = new AttestedCredentialData(aaguid, credentialId, coseKey);

        return new WebAuthnCredentialRecord(persistedData.username(), counter, attestedCredentialData);
    }

    /**
     * Record holding all the required persistent fields for logging back someone over WebAuthn.
     */
    public record RequiredPersistedData(
            /**
             * The user name. A single user name may be associated with multiple WebAuthn credentials.
             */
            String username,
            /**
             * The credential ID. This must be unique. See https://w3c.github.io/webauthn/#credential-id

View on GitHub (pinned to e1c734241f)

Solutions

  1. Re-register the WebAuthn credential so a fresh valid public key is persisted.
  2. Verify publicKey is stored/loaded losslessly (BLOB/bytea, not a fixed-length string column) and the base64 encoding round-trips.
  3. For EdDSA credentials, run on JDK 15+ (or with an EdDSA JCA provider installed).
  4. Check the cause chain (getCause()) of the IllegalArgumentException to distinguish InvalidKeySpecException from NoSuchAlgorithmException.

Example fix

// before: storing key as VARCHAR(64) -> truncated
@Column(length = 64) public String publicKey;

// after: lossless storage
@Column(columnDefinition = "bytea") public byte[] publicKey;
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity-check before deserialization: non-empty, X.509 DER starts with 0x30
byte[] pk = persistedData.publicKey();
if (pk == null || pk.length == 0 || (pk[0] & 0xff) != 0x30)
    throw new IllegalStateException("Persisted public key is missing or not X.509 encoded");

Try / catch

try {
    record = WebAuthnCredentialRecord.fromRequiredPersistedData(persistedData);
} catch (IllegalArgumentException e) {
    log.error("Stored public key unusable (cause: " + e.getCause() + "), re-registration required", e);
    throw new WebAuthnCredentialStorageException(e);
}

Prevention

When it happens

Trigger: Calling WebAuthnCredentialRecord.fromRequiredPersistedData with a RequiredPersistedData whose publicKey byte[] is corrupted, truncated, not a valid X.509 SubjectPublicKeyInfo, or whose algorithm requires an unavailable JCA provider (e.g. EdDSA on a JDK without Ed25519 support).

Common situations: Database blob/column mangled by manual edits or migration; key bytes re-encoded (e.g. base64 round trip done wrong) between persist and load; running EdDSA credentials (-8) on an old JDK (<15) lacking 'EdDSA' KeyFactory; byte[] truncated by a fixed-size column.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/40b19bbd27bc0507. Report an issue: GitHub.