错误信息
Could not parse PKey (OpenSSL::PKey::PKeyError)
也可能输出为
- OpenSSL::PKey::PKeyError: Could not parse PKey
- Neither PUB key nor PRIV key (OpenSSL::PKey::RSAError)
- invalid curve name (OpenSSL::PKey::ECError)
异常未被捕获时,Ruby 会打印“…: Could not parse PKey (OpenSSL::PKey::PKeyError)”。各个类专用的构造函数会抛出 `OpenSSL::PKey::RSAError` / `ECError`,并带有各自的文本。
Ruby openssl gem — OpenSSL::PKey.read / OpenSSL::PKey::RSA.new / OpenSSL::PKey::EC.new
含义
`OpenSSL::PKey.read` 尝试了 OpenSSL 支持的所有密钥格式(PEM 和 DER、公钥和私钥、用给定密码加密的密钥),全都失败了。Ruby 不会转述 OpenSSL 给出的具体原因,因此同一条文本既可能表示 PEM 损坏,也可能表示密码短语错误,还可能表示数据根本不是密钥。针对特定算法的构造函数也会以类似方式失败:`RSA.new` 报出“Neither PUB key nor PRIV key”,`EC.new` 报出“invalid curve name”(它会把无法解析的输入当作曲线名称)。
原因
换行符被替换成了字面的 \n
常见放在环境变量、Heroku/Render 配置变量或 YAML 字符串中的多行密钥,常常会变成带有 `\n` 序列的单行文本。
加密密钥缺少密码或密码错误
常见不带第二个参数的 `PKey.read(data)` 无法解密加密的密钥;密码错误也会产生同一个错误,而不是专门针对密码的错误。
不是 OpenSSL 能读取的密钥
偶见OpenSSH 公钥(`ssh-ed25519 AAAA…`)、JWK JSON 文档,或者在 PEM 块之前带有多余文本的证书链文件。
修复方法
- 1.
恢复换行符,并检查加载的内容
把 `\n` 序列还原为换行符,在启动时读取一次密钥,并断言它的类型以及是否为私钥。
ruby pem = ENV.fetch("JWT_PUBLIC_KEY").gsub("\\n", "\n") # restore real newlines key = OpenSSL::PKey.read(pem) raise "expected a public EC key" if key.private? || !key.is_a?(OpenSSL::PKey::EC) - 2.
把多行密钥存放在不会被破坏的地方
与单行的环境变量不同,Rails 加密凭证或挂载的机密文件能原样保留 PEM。
ruby # Rails: keep multi-line keys in encrypted credentials instead of ENV # bin/rails credentials:edit # jwt: # public_key: | # -----BEGIN PUBLIC KEY----- # ... key = OpenSSL::PKey.read(Rails.application.credentials.dig(:jwt, :public_key))