|
22 | 22 | */ |
23 | 23 | class Http_Message_Signature implements Signature_Standard { |
24 | 24 |
|
| 25 | + /** |
| 26 | + * Signature algorithms. |
| 27 | + * |
| 28 | + * @var int[][] |
| 29 | + */ |
| 30 | + private $algorithms = array( |
| 31 | + // RSA PKCS#1 v1.5. |
| 32 | + 'rsa-v1_5-sha256' => array( |
| 33 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 34 | + 'algo' => OPENSSL_ALGO_SHA256, |
| 35 | + ), |
| 36 | + 'rsa-v1_5-sha384' => array( |
| 37 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 38 | + 'algo' => OPENSSL_ALGO_SHA384, |
| 39 | + ), |
| 40 | + 'rsa-v1_5-sha512' => array( |
| 41 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 42 | + 'algo' => OPENSSL_ALGO_SHA512, |
| 43 | + ), |
| 44 | + |
| 45 | + // RSA PSS (note: not supported in openssl_verify() until PHP 8.1). |
| 46 | + 'rsa-pss-sha256' => array( |
| 47 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 48 | + 'algo' => OPENSSL_ALGO_SHA256, |
| 49 | + ), |
| 50 | + 'rsa-pss-sha384' => array( |
| 51 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 52 | + 'algo' => OPENSSL_ALGO_SHA384, |
| 53 | + ), |
| 54 | + 'rsa-pss-sha512' => array( |
| 55 | + 'type' => OPENSSL_KEYTYPE_RSA, |
| 56 | + 'algo' => OPENSSL_ALGO_SHA512, |
| 57 | + ), |
| 58 | + |
| 59 | + // ECDSA. |
| 60 | + 'ecdsa-p256-sha256' => array( |
| 61 | + 'type' => OPENSSL_KEYTYPE_EC, |
| 62 | + 'algo' => OPENSSL_ALGO_SHA256, |
| 63 | + ), |
| 64 | + 'ecdsa-p384-sha384' => array( |
| 65 | + 'type' => OPENSSL_KEYTYPE_EC, |
| 66 | + 'algo' => OPENSSL_ALGO_SHA384, |
| 67 | + ), |
| 68 | + 'ecdsa-p521-sha512' => array( |
| 69 | + 'type' => OPENSSL_KEYTYPE_EC, |
| 70 | + 'algo' => OPENSSL_ALGO_SHA512, |
| 71 | + ), |
| 72 | + ); |
| 73 | + |
25 | 74 | /** |
26 | 75 | * Digest algorithms. |
27 | 76 | * |
@@ -248,69 +297,52 @@ private function verify_content_digest( $headers, $body ) { |
248 | 297 | * @return int|\WP_Error OpenSSL algorithm constant or WP_Error. |
249 | 298 | */ |
250 | 299 | private function verify_algorithm( $alg_string, $public_key ) { |
251 | | - $alg_string = \strtolower( $alg_string ); |
252 | | - if ( \strpos( $alg_string, 'rsa-pss-' ) === 0 && \version_compare( PHP_VERSION, '8.1.0', '<' ) ) { |
253 | | - return new \WP_Error( 'unsupported_pss', 'RSA-PSS algorithms are not supported.' ); |
254 | | - } |
255 | | - |
256 | 300 | $details = \openssl_pkey_get_details( $public_key ); |
257 | 301 | if ( ! isset( $details['type'] ) ) { |
258 | 302 | return new \WP_Error( 'invalid_key_details', 'Unable to read public key details.' ); |
259 | 303 | } |
260 | 304 |
|
261 | | - $map = array( |
262 | | - // RSA PKCS#1 v1.5. |
263 | | - 'rsa-v1_5-sha256' => array( |
264 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
265 | | - 'algo' => OPENSSL_ALGO_SHA256, |
266 | | - ), |
267 | | - 'rsa-v1_5-sha384' => array( |
268 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
269 | | - 'algo' => OPENSSL_ALGO_SHA384, |
270 | | - ), |
271 | | - 'rsa-v1_5-sha512' => array( |
272 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
273 | | - 'algo' => OPENSSL_ALGO_SHA512, |
274 | | - ), |
275 | | - |
276 | | - // RSA PSS (note: not supported in openssl_verify() until PHP 8.1). |
277 | | - 'rsa-pss-sha256' => array( |
278 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
279 | | - 'algo' => OPENSSL_ALGO_SHA256, |
280 | | - ), |
281 | | - 'rsa-pss-sha384' => array( |
282 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
283 | | - 'algo' => OPENSSL_ALGO_SHA384, |
284 | | - ), |
285 | | - 'rsa-pss-sha512' => array( |
286 | | - 'type' => OPENSSL_KEYTYPE_RSA, |
287 | | - 'algo' => OPENSSL_ALGO_SHA512, |
288 | | - ), |
289 | | - |
290 | | - // ECDSA. |
291 | | - 'ecdsa-p256-sha256' => array( |
292 | | - 'type' => OPENSSL_KEYTYPE_EC, |
293 | | - 'algo' => OPENSSL_ALGO_SHA256, |
294 | | - ), |
295 | | - 'ecdsa-p384-sha384' => array( |
296 | | - 'type' => OPENSSL_KEYTYPE_EC, |
297 | | - 'algo' => OPENSSL_ALGO_SHA384, |
298 | | - ), |
299 | | - 'ecdsa-p521-sha512' => array( |
300 | | - 'type' => OPENSSL_KEYTYPE_EC, |
301 | | - 'algo' => OPENSSL_ALGO_SHA512, |
302 | | - ), |
303 | | - ); |
| 305 | + // If alg_string is empty, determine algorithm based on public key. |
| 306 | + if ( empty( $alg_string ) ) { |
| 307 | + switch ( $details['type'] ) { |
| 308 | + case \OPENSSL_KEYTYPE_RSA: |
| 309 | + $bits = $details['bits'] ?? 2048; |
| 310 | + |
| 311 | + if ( $bits >= 4 * KB_IN_BYTES ) { |
| 312 | + return \OPENSSL_ALGO_SHA512; |
| 313 | + } elseif ( $bits >= 3 * KB_IN_BYTES ) { |
| 314 | + return \OPENSSL_ALGO_SHA384; |
| 315 | + } else { |
| 316 | + return \OPENSSL_ALGO_SHA256; |
| 317 | + } |
| 318 | + |
| 319 | + case \OPENSSL_KEYTYPE_EC: |
| 320 | + switch ( $details['ec']['curve_name'] ?? '' ) { |
| 321 | + case 'prime256v1': |
| 322 | + case 'secp256r1': |
| 323 | + return \OPENSSL_ALGO_SHA256; |
| 324 | + case 'secp384r1': |
| 325 | + return \OPENSSL_ALGO_SHA384; |
| 326 | + case 'secp521r1': |
| 327 | + return \OPENSSL_ALGO_SHA512; |
| 328 | + } |
| 329 | + } |
| 330 | + } |
| 331 | + |
| 332 | + $alg_string = \strtolower( $alg_string ); |
| 333 | + if ( \strpos( $alg_string, 'rsa-pss-' ) === 0 && \version_compare( PHP_VERSION, '8.1.0', '<' ) ) { |
| 334 | + return new \WP_Error( 'unsupported_pss', 'RSA-PSS algorithms are not supported.' ); |
| 335 | + } |
304 | 336 |
|
305 | | - if ( ! isset( $map[ $alg_string ] ) ) { |
| 337 | + if ( ! isset( $this->algorithms[ $alg_string ] ) ) { |
306 | 338 | return new \WP_Error( 'unsupported_alg', 'Unsupported or unknown alg parameter: ' . $alg_string ); |
307 | 339 | } |
308 | 340 |
|
309 | | - if ( $map[ $alg_string ]['type'] !== $details['type'] ) { |
| 341 | + if ( $this->algorithms[ $alg_string ]['type'] !== $details['type'] ) { |
310 | 342 | return new \WP_Error( 'alg_key_mismatch', 'Algorithm does not match public key type.' ); |
311 | 343 | } |
312 | 344 |
|
313 | | - return $map[ $alg_string ]['algo']; |
| 345 | + return $this->algorithms[ $alg_string ]['algo']; |
314 | 346 | } |
315 | 347 |
|
316 | 348 | /** |
|
0 commit comments