Allow constructing a public-only RSA key with openssl_pkey_new()
まだ誰も着手していません。
- 主要言語
- C
- スター
- 40.4k
- フォーク
- 8.1k
- 平均マージ
- 2日 13時間
- マージ済み PR(30日)
- 96
説明
Description
openssl_pkey_new() can construct a public key directly from raw parameters for every asymmetric key type except RSA:
['ec' => ['curve_name' => …, 'x' => …, 'y' => …]]→ public EC key ✅['ed25519' => ['pub_key' => …]]/['ed448' => …]→ public EdDSA key ✅['dsa' | 'dh' => ['pub_key' => …]]→ public key ✅['rsa' => ['n' => …, 'e' => …]]→ ❌ a private exponentdis mandatory, and the result is always flagged private
So there is no way to obtain an RSA public key object from n and e that openssl_verify() will accept:
// (1) Without d — construction fails outright:
var_dump(openssl_pkey_new(['rsa' => ['n' => $n, 'e' => $e]])); // bool(false)
// (2) With a dummy d — builds, but is flagged private, so verify() refuses it:
$k = openssl_pkey_new(['rsa' => ['n' => $n, 'e' => $e, 'd' => "\x00"]]);
openssl_verify($msg, $sig, $k, OPENSSL_ALGO_SHA256);
// Warning: openssl_verify(): Don't know how to get public key from this private key
// Warning: openssl_verify(): Supplied key param cannot be coerced into a public key
The only workarounds today are to build a throwaway "private" key with a placeholder d, then round-trip it back out via openssl_pkey_get_details($k)['key'] and reload with openssl_pkey_get_public(), or to hand-encode a DER SubjectPublicKeyInfo in userland. Both are awkward for something every other key type supports natively.
Why this is worth adding
a) Consistency — RSA is the only outlier. In ext/openssl, php_openssl_pkey_init_dsa(), _dh(), _ec(), and the curve-25519/448 path all take an is_private out-parameter, derive it from whether private material was supplied, and build public-only keys just fine. php_openssl_pkey_init_rsa() alone (i) hard-requires d, (ii) never computes is_private, and (iii) its caller in openssl_pkey_new() hardcodes is_private = true. Bringing RSA in line with the others is a small, localized change.
b) WebAuthn / COSE key conversion. WebAuthn credential public keys arrive as COSE_Key maps (RFC 9052; RSA parameters per RFC 8230) — i.e. raw n and e bytes for RS256. Relying parties need to turn those into an OpenSSL key purely to verify assertion signatures. For EC2 (ES256) and OKP (EdDSA) keys this is already a clean one-liner via openssl_pkey_new(); for RSA it forces the dummy-d PEM round-trip above or a hand-rolled ASN.1 encoder. Public-only RSA construction would let libraries handle all three COSE key types uniformly, with zero userland ASN.1.
Suggested implementation
Mirror the existing init_dsa/init_ec pattern:
- give
php_openssl_pkey_init_rsa()abool *is_privateout-param; - make
doptional (requirenande), pushOSSL_PKEY_PARAM_RSA_Donly when present, and set*is_private = (d != NULL); - select
EVP_PKEY_PUBLIC_KEYvsEVP_PKEY_KEYPAIRaccordingly (v3 backend), and passd == NULLthrough toRSA_set0_key()(v1 backend, which already permits it); - have the
rsabranch ofopenssl_pkey_new()pass the flag tophp_openssl_pkey_object_init(), exactly like thedsa/ecbranches.
This is purely additive — keys constructed with d stay flagged private, so no BC break. Happy to send a PR with tests if this is welcome.
PHP Version
master (8.5-dev); behaviour also confirmed on 8.4.23.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
php_openssl_pkey_init_rsa() と openssl_pkey_new() の rsa ブランチから始め、既存の init_dsa および init_ec のパスと比較します。n/e のみを含む RSA キーが openssl_verify() に受け入れられる一方で、d を含むキーは秘密のままであることを検証し、両方のケースを対象とするテストを追加します。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- c, php
- 領域
- cryptography
- issue の種類
- 機能追加
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 静か
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 68/100