basecamp/fizzy · error · ActionPack::WebAuthn::UnsupportedKeyTypeError

Unsupported EC curve: #{curve}

Error message

Unsupported EC curve: #{curve}

What it means

For EC2 keys the library only builds P-256 (prime256v1) keys: the COSE curve label (-1) must equal 1. Any other curve value — 2 (P-384), 3 (P-521), 0/nil (missing) — raises UnsupportedKeyTypeError with the value interpolated.

Source

Thrown at lib/action_pack/web_authn/cose_key.rb:115

  # Returns an +OpenSSL::PKey::EC+ for EC2 keys, +OpenSSL::PKey::RSA+ for
  # RSA keys, or an Ed25519 key for OKP keys, suitable for use with
  # +OpenSSL::PKey#verify+.
  #
  # Raises +UnsupportedKeyTypeError+ if the key type, algorithm, or curve
  # is not supported.
  def to_openssl_key
    case [ key_type, algorithm ]
    when [ EC2, ES256 ] then build_ec2_es256_key
    when [ OKP, EDDSA ] then build_okp_eddsa_key
    when [ RSA, RS256 ] then build_rsa_rs256_key
    else raise ActionPack::WebAuthn::UnsupportedKeyTypeError, "Unsupported COSE key type/algorithm: #{key_type}/#{algorithm}"
    end
  end

  private
    def build_ec2_es256_key
      curve = parameters[EC2_CURVE_LABEL]
      raise ActionPack::WebAuthn::UnsupportedKeyTypeError, "Unsupported EC curve: #{curve}" unless curve == P256

      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)

View on GitHub (pinned to 7aabe74580)

Solutions

  1. Restrict client registration to ES256/RS256/EdDSA via pubKeyCredParams so non-P-256 EC keys are never created.
  2. Pre-check parameters[-1] == 1 before calling to_openssl_key and reject with a specific 'curve not supported' message.
  3. Rescue UnsupportedKeyTypeError at registration and ask the user to use a different authenticator.
  4. Verify the COSE map has labels 1, 3, -1, -2, -3 before conversion — missing labels produce confusing downstream errors.

Example fix

# before
key = cose_key.to_openssl_key # raises for curve 2/3/nil

# after — gate on the supported curve first
unless cose_key.parameters[CoseKey::EC2_CURVE_LABEL] == CoseKey::P256
  return render json: { error: 'credential curve not supported' }, status: :bad_request
end
key = cose_key.to_openssl_key
Defensive patterns

Strategy: validation

Validate before calling

if cose_key.key_type == ActionPack::WebAuthn::CoseKey::EC2 && cose_key.parameters[ActionPack::WebAuthn::CoseKey::EC2_CURVE_LABEL] != ActionPack::WebAuthn::CoseKey::P256
  return render json: { error: 'credential curve not supported' }, status: :bad_request
end

Type guard

def supported_ec2_curve?(cose_key)
  cose_key.parameters[ActionPack::WebAuthn::CoseKey::EC2_CURVE_LABEL] == ActionPack::WebAuthn::CoseKey::P256
end

Try / catch

begin
  key = cose_key.to_openssl_key
rescue ActionPack::WebAuthn::UnsupportedKeyTypeError => e
  render json: { error: e.message }, status: :bad_request
end

Prevention

When it happens

Trigger: A credential attested as ES256 whose COSE map carries curve 2 or 3 (mismatched metadata), a P-384 smart-card credential, or a truncated COSE map where label -1 is absent so curve is nil.

Common situations: Authenticators or middleware that emit ES384 keys while labeling the algorithm ES256; conformance-test vectors using exotic curves; hand-assembled COSE maps missing the crv (-1) entry.

Related errors


AI-assisted analysis of basecamp/fizzy@7aabe74580 (2026-08-21). Data as JSON: /api/errors/ee445a62217decac. Report an issue: GitHub.