Make WordPress Core

Changeset 45345 for trunk


Ignore:
Timestamp:
05/17/2019 11:05:45 AM (7 years ago)
Author:
tellyworth
Message:

Upgrade/Install: Don't run signature verify on slow 32-bit systems.

The sodium_compat library can be very slow for certain operations on 32-bit architectures, which can lead to web server timeouts while attempting to verify an update. This adds a runtime speed check to skip signature verification on systems that would otherwise time out. Includes simple unit tests.

Props dd32, paragoninitiativeenterprises.
See #47186.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r45298 r45345  
    12001200        }
    12011201
     1202        // Verify runtime speed of Sodium_Compat is acceptable.
     1203        if ( ! extension_loaded( 'sodium' ) && ! ParagonIE_Sodium_Compat::polyfill_is_fast() ) {
     1204                $sodium_compat_is_fast = false;
     1205
     1206                // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
     1207                if ( method_exists( 'ParagonIE_Sodium_Compat', 'runtime_speed_test' ) ) {
     1208                        // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
     1209                        $old_fastMult                      = ParagonIE_Sodium_Compat::$fastMult;
     1210                        ParagonIE_Sodium_Compat::$fastMult = true;
     1211                        $sodium_compat_is_fast             = ParagonIE_Sodium_Compat::runtime_speed_test( 100, 10 );
     1212                        ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
     1213                }
     1214
     1215                // This cannot be performed in a reasonable amount of time
     1216                // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
     1217                if ( ! $sodium_compat_is_fast ) {
     1218                        return new WP_Error(
     1219                                'signature_verification_unsupported',
     1220                                sprintf(
     1221                                        /* translators: 1: The filename of the package. */
     1222                                        __( 'The authenticity of %1$s could not be verified as signature verification is unavailable on this system.' ),
     1223                                        '<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
     1224                                ),
     1225                                array(
     1226                                        'php'                => phpversion(),
     1227                                        'sodium'             => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
     1228                                        'polyfill_is_fast'   => false,
     1229                                        'max_execution_time' => ini_get( 'max_execution_time' ),
     1230                                )
     1231                        );
     1232                }
     1233        }
     1234
    12021235        if ( ! $signatures ) {
    12031236                return new WP_Error(
  • trunk/tests/phpunit/tests/file.php

    r42343 r45345  
    184184        }
    185185
     186        /**
     187         * @ticket 47186
     188         */
     189        function test_file_signature_functions_as_expected() {
     190                $file = wp_tempnam();
     191                file_put_contents( $file, 'WordPress' );
     192
     193                // The signature of 'WordPress' after SHA384 hashing, for verification against the key within self::filter_trust_plus85Tq_key().
     194                $expected_signature = 'PmNv0b1ziwJAsVhjdpjd4+PQZidZWSlBm5b+GbbwE9m9HVKDFhEyvyRTHkRYOLypB8P2YvbW7CoOMZqGh8mEAA==';
     195
     196                add_filter( 'wp_trusted_keys', array( $this, 'filter_trust_plus85Tq_key' ) );
     197
     198                // Measure how long the call takes.
     199                $timer_start = microtime( 1 );
     200                $verify      = verify_file_signature( $file, $expected_signature, 'WordPress' );
     201                $timer_end   = microtime( 1 );
     202                $time_taken  = ( $timer_end - $timer_start );
     203
     204                unlink( $file );
     205                remove_filter( 'wp_trusted_keys', array( $this, 'filter_trust_plus85Tq_key' ) );
     206
     207                // verify_file_signature() should intentionally never take more than 10s to run.
     208                $this->assertLessThan( 10, $time_taken, 'verify_file_signature() took longer than 10 seconds.' );
     209
     210                // Check to see if the system parameters prevent signature verifications.
     211                if ( is_wp_error( $verify ) && 'signature_verification_unsupported' == $verify->get_error_code() ) {
     212                        $this->markTestSkipped( 'This system does not support Signature Verification.' );
     213                }
     214
     215                $this->assertNotWPError( $verify );
     216                $this->assertTrue( $verify );
     217        }
     218
     219        /**
     220         * @ticket 47186
     221         */
     222        function test_file_signature_expected_failure() {
     223                $file = wp_tempnam();
     224                file_put_contents( $file, 'WordPress' );
     225
     226                // Test an invalid signature.
     227                $expected_signature = base64_encode( str_repeat( 'A', SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES ) );
     228                $verify             = verify_file_signature( $file, $expected_signature, 'WordPress' );
     229                unlink( $file );
     230
     231                if ( is_wp_error( $verify ) && 'signature_verification_unsupported' == $verify->get_error_code() ) {
     232                        $this->markTestSkipped( 'This system does not support Signature Verification.' );
     233                }
     234
     235                $this->assertWPError( $verify );
     236                $this->assertEquals( 'signature_verification_failed', $verify->get_error_code() );
     237        }
     238
     239        function filter_trust_plus85Tq_key( $keys ) {
     240                // A static once-off key used to verify verify_file_signature() works as expected.
     241                $keys[] = '+85TqMhxQVAYVW4BSCVkJQvZH4q7z8I9lePbvngvf7A=';
     242
     243                return $keys;
     244        }
    186245}
Note: See TracChangeset for help on using the changeset viewer.