openssl gem 随 Ruby 一起发布,封装了系统中的 OpenSSL——在 ruby:4.0.7 镜像中为 3.5.7,gem 版本为 4.0.2。OpenSSL::PKey::EC#sign(digest, data) 生成 ASN.1 DER 签名,使用随机 nonce,不做 low-S 规范化;verify 接受 high-S。dsa_sign_asn1 对你已经计算好的摘要签名。
格式错误的签名会抛出异常,而不是返回 false:64 字节的原始 r‖s 签名或 3 字节的数据块会抛出 OpenSSL::PKey::PKeyError: EVP_DigestVerify,而针对另一条消息、格式正确的签名则返回 false。只检查布尔值的代码遇到 JWS 风格的签名会崩溃,因此要么用 rescue 捕获 PKeyError,要么像示例那样先做转换;DER ⇄ 原始格式转换器可以并排显示两种形式。
在 OpenSSL 3 上密钥是不可变的:对已有的 EC 密钥赋值 private_key 时抛出了 pkeys are immutable on OpenSSL 3.0,那些通过设置点或标量来构造密钥的旧教程因此不再适用。应改为从 DER 或 PEM 构造密钥——裸 SEC1 点必须先包装进 SPKI 结构。注意各个方法写出的内容:私钥上的 to_pem 写出包含秘密值的 SEC1 EC PRIVATE KEY,private_to_pem 写出 PKCS#8,而可以公开发布的是 public_to_pem 的输出。
支持的曲线与 OpenSSL 一致:P-224 到 P-521、secp256k1 和 Brainpool r1 曲线,另外可通过 OpenSSL::PKey.generate_key 使用 Ed25519 和 Ed448。同一套通用 API 完成了 ML-DSA-44/65/87 和 SLH-DSA 密钥的生成、签名与验证;ML-KEM 密钥可以生成,但 4.0.2 中的 PKey 不提供封装方法。JWT 库 ruby-jwt 就构建在这个 gem 之上。