basecamp/fizzy · error · ActionPack::WebAuthn::InvalidKeyError
Invalid EC2 key: #{error.message}
Error message
Invalid EC2 key: #{error.message} What it means
When the coordinate lengths pass, the library packs 0x04||x||y into ASN.1 and hands it to OpenSSL::PKey::EC.new. If OpenSSL rejects it — most commonly because the point is not on the P-256 curve — the OpenSSL::PKey::PKeyError is re-raised as InvalidKeyError 'Invalid EC2 key: <openssl message>'. Structurally valid bytes but mathematically invalid key material.
Source
Thrown at lib/action_pack/web_authn/cose_key.rb:135
x = parameters[EC2_X_LABEL]
y = parameters[EC2_Y_LABEL]
raise ActionPack::WebAuthn::InvalidKeyError, "Missing EC2 key coordinates" if x.nil? || y.nil?
raise ActionPack::WebAuthn::InvalidKeyError, "Invalid EC2 coordinate length" unless x.bytesize == P256_COORDINATE_LENGTH && y.bytesize == P256_COORDINATE_LENGTH
# Uncompressed point format: 0x04 || x || y
public_key_bytes = [ UNCOMPRESSED_POINT_MARKER, *x.bytes, *y.bytes ].pack("C*")
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
OpenSSL::ASN1::ObjectId("prime256v1")
]),
OpenSSL::ASN1::BitString(public_key_bytes)
])
OpenSSL::PKey::EC.new(asn1.to_der)
rescue OpenSSL::PKey::PKeyError => error
raise ActionPack::WebAuthn::InvalidKeyError, "Invalid EC2 key: #{error.message}"
end
def build_okp_eddsa_key
curve = parameters[OKP_CURVE_LABEL]
raise ActionPack::WebAuthn::UnsupportedKeyTypeError, "Unsupported OKP curve: #{curve}" unless curve == ED25519
x = parameters[OKP_X_LABEL]
raise ActionPack::WebAuthn::InvalidKeyError, "Missing OKP key coordinate" if x.nil?
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::ObjectId("ED25519")
]),
OpenSSL::ASN1::BitString(x)
])
OpenSSL::PKey.read(asn1.to_der)
rescue OpenSSL::PKey::PKeyError => errorView on GitHub (pinned to 7aabe74580)
Solutions
- Treat it as a failed registration: rescue InvalidKeyError, log the OpenSSL message, and return 400 — never fall back to partial verification.
- If it reproduces with one specific authenticator, capture a fresh registration from it and compare coordinates; a consistent failure indicates a firmware/encoder bug.
- Verify the transport path for byte corruption (compare the client-side hash of the key bytes with the server-side one).
- In tests, generate valid points with OpenSSL::PKey::EC.new('prime256v1').generate_key instead of random bytes.
Example fix
# before
key = cose_key.to_openssl_key # raises InvalidKeyError: point not on curve
# after — fail registration cleanly on any invalid key material
begin
key = cose_key.to_openssl_key
rescue ActionPack::WebAuthn::InvalidKeyError => e
Rails.logger.warn { "Rejected invalid credential key: #{e.message}" }
return render json: { error: 'credential key invalid' }, status: :bad_request
end Defensive patterns
Strategy: try-catch
Try / catch
begin
key = cose_key.to_openssl_key
rescue ActionPack::WebAuthn::InvalidKeyError => e
Rails.logger.warn { "Rejected invalid EC2 key: #{e.message}" }
render json: { error: 'credential key invalid' }, status: :bad_request
end Prevention
- Never fall back to partial verification when key construction fails — fail the registration.
- In tests, generate real P-256 keys with OpenSSL instead of random 32-byte strings.
- Log the underlying OpenSSL message; 'point not on curve' almost always means corrupted transport or forged input.
When it happens
Trigger: Coordinates that are each exactly 32 bytes but do not satisfy the curve equation y^2 = x^3 - 3x + b mod p — corrupt values, bit-flipped transport, forged attestation attempts, or random test bytes used as coordinates.
Common situations: Fuzz tests feeding random 32-byte strings; fixtures where x/y were swapped or truncated-then-padded incorrectly; tampered registration payloads; authenticator firmware bugs (rare).
Related errors
- Unsupported EC curve: #{curve}
- Invalid EC2 coordinate length
- Missing OKP key coordinate
- Invalid OKP key: #{error.message}
- Missing RSA key parameters
AI-assisted analysis of basecamp/fizzy@7aabe74580 (2026-08-21).
Data as JSON: /api/errors/4429bca25748ad03.
Report an issue: GitHub.