{"record":{"id":"e3c4c1832d7c5039","repo":"basecamp/fizzy","slug":"invalid-rsa-key-error-message","errorCode":null,"errorMessage":"Invalid RSA key: #{error.message}","messagePattern":"Invalid RSA key: #(.+?)","errorType":"exception","errorClass":"ActionPack::WebAuthn::InvalidKeyError","httpStatus":null,"severity":"error","filePath":"lib/action_pack/web_authn/cose_key.rb","lineNumber":181,"sourceCode":"      n = OpenSSL::BN.new(n_bytes, 2)\n      e = OpenSSL::BN.new(e_bytes, 2)\n\n      asn1 = OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::Sequence([\n          OpenSSL::ASN1::ObjectId(\"rsaEncryption\"),\n          OpenSSL::ASN1::Null.new(nil)\n        ]),\n        OpenSSL::ASN1::BitString(\n          OpenSSL::ASN1::Sequence([\n            OpenSSL::ASN1::Integer(n),\n            OpenSSL::ASN1::Integer(e)\n          ]).to_der\n        )\n      ])\n\n      OpenSSL::PKey::RSA.new(asn1.to_der)\n    rescue OpenSSL::PKey::PKeyError => error\n      raise ActionPack::WebAuthn::InvalidKeyError, \"Invalid RSA key: #{error.message}\"\n    end\nend\n","sourceCodeStart":163,"sourceCodeEnd":184,"githubUrl":"https://github.com/basecamp/fizzy/blob/7aabe7458060d8a1759a53b7ede39e74e6c0b20d/lib/action_pack/web_authn/cose_key.rb#L163-L184","documentation":"ActionPack::WebAuthn::CoseKey wrapped an OpenSSL::PKey::PKeyError from OpenSSL::PKey::RSA.new: n and e (labels -1/-2) were present and passed the 2048-bit gate, but the values do not form a loadable RSA public key. OpenSSL::BN.new(bytes, 2) accepts almost any byte string, so malformed input usually survives until this final DER parse. The library re-raises as InvalidKeyError with the underlying OpenSSL message (for example an ASN.1/RSAError reason) appended.","triggerScenarios":"Calling to_openssl_key on an RS256 key where -1/-2 are wrong-typed or corrupted byte strings (hex text, sign-bit mistakes, swapped n and e, or garbage from misaligned slicing) so OpenSSL::BN accepts them but OpenSSL::PKey::RSA.new(asn1.to_der) raises during the final parse.","commonSituations":"Re-encoding keys through JSON or a database (bytes to hex to binary mismatches) before building the COSE map; test key factories with endian/sign errors; non-canonical CBOR decoders altering byte strings; credentials relayed through proxies that mangle binary payloads.","solutions":["Verify -1/-2 are raw big-endian byte strings, not hex or base64 text: OpenSSL::BN.new(bytes, 2) accepts anything, so garbage only surfaces at OpenSSL::PKey::RSA.new","Re-derive both parameters from a known-good RSA public key (rsa.n.to_s(2), rsa.e.to_s(2)) and compare with what your code produced","Check for encoding drift upstream: JSON round-trips, base64url padding, or CBOR libraries that alter byte strings","Rescue ActionPack::WebAuthn::InvalidKeyError at registration and surface a malformed-credential error to the client, logging error.message which carries the OpenSSL reason"],"exampleFix":"# before: exponent passed as hex text; BN accepts it, RSA.new fails later\ne_bytes = '010001'\n\n# after: raw big-endian bytes\ne_bytes = ['010001'].pack('H*') # or OpenSSL::BN.new(65537).to_s(2)","handlingStrategy":"try-catch","validationCode":"e = OpenSSL::BN.new(cose.parameters[-2], 2)\nreturn unless [3, 5, 17, 257, 65537].include?(e.to_i) # conventional RSA public exponents\ncose.to_openssl_key","typeGuard":null,"tryCatchPattern":"begin\n  openssl_key = cose_key.to_openssl_key\nrescue ActionPack::WebAuthn::InvalidKeyError => e\n  # e.message embeds the OpenSSL parse reason; keep it in the failure log\n  render json: { error: e.message }, status: :unprocessable_entity\nend","preventionTips":["Keep COSE byte strings raw; convert hex/base64 at the transport edge, before building the parameters map","Derive n and e for fixtures from a real OpenSSL::PKey::RSA object rather than constants","Rescue InvalidKeyError and log error.message so the underlying OpenSSL reason is visible","Round-trip test any key re-encoding path (JSON, DB blobs) with a known-good credential"],"tags":["webauthn","cose","openssl","rsa","asn1"],"backgroundTag":"openssl-key-parse-failure","analyzedSha":"7aabe7458060d8a1759a53b7ede39e74e6c0b20d","analyzedAt":"2026-08-21T18:33:25.349Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}