Skip to content

Commit

Permalink
Upgrade/Install: Don't run signature verify on slow 32-bit systems.
Browse files Browse the repository at this point in the history
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.

Merges [45345] to the 5.2 branch.

Props dd32, paragoninitiativeenterprises, tellyworth.
Fixes #47186.

git-svn-id: https://develop.svn.wordpress.org/branches/5.2@45356 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
desrosj committed May 17, 2019
1 parent 8005232 commit 8fe8dec
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/wp-admin/includes/file.php
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,39 @@ function verify_file_signature( $filename, $signatures, $filename_for_errors = f

}

// Verify runtime speed of Sodium_Compat is acceptable.
if ( ! extension_loaded( 'sodium' ) && ! ParagonIE_Sodium_Compat::polyfill_is_fast() ) {
$sodium_compat_is_fast = false;

// Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
if ( method_exists( 'ParagonIE_Sodium_Compat', 'runtime_speed_test' ) ) {
// Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
$old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
ParagonIE_Sodium_Compat::$fastMult = true;
$sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test( 100, 10 );
ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
}

// This cannot be performed in a reasonable amount of time
// https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
if ( ! $sodium_compat_is_fast ) {
return new WP_Error(
'signature_verification_unsupported',
sprintf(
/* translators: 1: The filename of the package. */
__( 'The authenticity of %1$s could not be verified as signature verification is unavailable on this system.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
array(
'php' => phpversion(),
'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
'polyfill_is_fast' => false,
'max_execution_time' => ini_get( 'max_execution_time' ),
)
);
}
}

if ( ! $signatures ) {
return new WP_Error(
'signature_verification_no_signature',
Expand Down
59 changes: 59 additions & 0 deletions tests/phpunit/tests/file.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,63 @@ function data_wp_tempnam_filenames() {
);
}

/**
* @ticket 47186
*/
function test_file_signature_functions_as_expected() {
$file = wp_tempnam();
file_put_contents( $file, 'WordPress' );

// The signature of 'WordPress' after SHA384 hashing, for verification against the key within self::filter_trust_plus85Tq_key().
$expected_signature = 'PmNv0b1ziwJAsVhjdpjd4+PQZidZWSlBm5b+GbbwE9m9HVKDFhEyvyRTHkRYOLypB8P2YvbW7CoOMZqGh8mEAA==';

add_filter( 'wp_trusted_keys', array( $this, 'filter_trust_plus85Tq_key' ) );

// Measure how long the call takes.
$timer_start = microtime( 1 );
$verify = verify_file_signature( $file, $expected_signature, 'WordPress' );
$timer_end = microtime( 1 );
$time_taken = ( $timer_end - $timer_start );

unlink( $file );
remove_filter( 'wp_trusted_keys', array( $this, 'filter_trust_plus85Tq_key' ) );

// verify_file_signature() should intentionally never take more than 10s to run.
$this->assertLessThan( 10, $time_taken, 'verify_file_signature() took longer than 10 seconds.' );

// Check to see if the system parameters prevent signature verifications.
if ( is_wp_error( $verify ) && 'signature_verification_unsupported' == $verify->get_error_code() ) {
$this->markTestSkipped( 'This system does not support Signature Verification.' );
}

$this->assertNotWPError( $verify );
$this->assertTrue( $verify );
}

/**
* @ticket 47186
*/
function test_file_signature_expected_failure() {
$file = wp_tempnam();
file_put_contents( $file, 'WordPress' );

// Test an invalid signature.
$expected_signature = base64_encode( str_repeat( 'A', SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES ) );
$verify = verify_file_signature( $file, $expected_signature, 'WordPress' );
unlink( $file );

if ( is_wp_error( $verify ) && 'signature_verification_unsupported' == $verify->get_error_code() ) {
$this->markTestSkipped( 'This system does not support Signature Verification.' );
}

$this->assertWPError( $verify );
$this->assertEquals( 'signature_verification_failed', $verify->get_error_code() );
}

function filter_trust_plus85Tq_key( $keys ) {
// A static once-off key used to verify verify_file_signature() works as expected.
$keys[] = '+85TqMhxQVAYVW4BSCVkJQvZH4q7z8I9lePbvngvf7A=';

return $keys;
}
}

0 comments on commit 8fe8dec

Please sign in to comment.