WordPress.org

Make WordPress Core


Ignore:
Timestamp:
04/24/2019 07:43:29 AM (3 months ago)
Author:
tellyworth
Message:

Upgrade/install: fix verification bugs and scale back signature checks.

This fixes several bugs in the signature verification code:
Disables signature checks on certain incompatible PHP versions that cause math errors when opcache is enabled;
Prevents a spurious URL and subsequent error when downloading a zip file with query arguments;
Prevents errors triggered by third-party upgrade scripts as per #46615;
Disables signature tests for Plugins, Themes, and Translations, leaving only core updates.

At the 5.2 release the API servers will only provide signatures for core update packages, which is why messages are suppressed for plugins and other package types. Signatures for those other items will become available later.

Props dd32.
See #39309, #46615

File:
1 edited

Legend:

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

    r45232 r45262  
    969969 * @since 5.2.0 Signature Verification with SoftFail was added.
    970970 *
    971  * @param string $url                The URL of the file to download.
    972  * @param int    $timeout            The timeout for the request to download the file. Default 300 seconds.
    973  * @param bool   $signature_softfail Whether to allow Signature Verification to softfail. Default true.
     971 * @param string $url                    The URL of the file to download.
     972 * @param int    $timeout                The timeout for the request to download the file. Default 300 seconds.
     973 * @param bool   $signature_verification Whether to perform Signature Verification. Default false.
    974974 * @return string|WP_Error Filename on success, WP_Error on failure.
    975975 */
    976 function download_url( $url, $timeout = 300, $signature_softfail = true ) {
     976function download_url( $url, $timeout = 300, $signature_verification = false ) {
    977977    //WARNING: The file is not automatically deleted, The script must unlink() the file.
    978978    if ( ! $url ) {
     
    10381038    }
    10391039
    1040     /**
    1041      * Filters the list of hosts which should have Signature Verification attempted on.
    1042      *
    1043      * @since 5.2.0
    1044      *
    1045      * @param array List of hostnames.
    1046      */
    1047     $signed_hostnames       = apply_filters( 'wp_signature_hosts', array( 'wordpress.org', 'downloads.wordpress.org', 's.w.org' ) );
    1048     $signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true );
    1049 
    1050     // Perform the valiation
     1040    // If the caller expects signature verification to occur, check to see if this URL supports it.
     1041    if ( $signature_verification ) {
     1042        /**
     1043         * Filters the list of hosts which should have Signature Verification attempteds on.
     1044         *
     1045         * @since 5.2.0
     1046         *
     1047         * @param array List of hostnames.
     1048         */
     1049        $signed_hostnames       = apply_filters( 'wp_signature_hosts', array( 'wordpress.org', 'downloads.wordpress.org', 's.w.org' ) );
     1050        $signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true );
     1051    }
     1052
     1053    // Perform signature valiation if supported.
    10511054    if ( $signature_verification ) {
    10521055        $signature = wp_remote_retrieve_header( $response, 'x-content-signature' );
     
    10541057            // Retrieve signatures from a file if the header wasn't included.
    10551058            // WordPress.org stores signatures at $package_url.sig
    1056             $signature_request = wp_safe_remote_get( $url . '.sig' );
    1057             if ( ! is_wp_error( $signature_request ) && 200 === wp_remote_retrieve_response_code( $signature_request ) ) {
    1058                 $signature = explode( "\n", wp_remote_retrieve_body( $signature_request ) );
     1059
     1060            $signature_url = false;
     1061            $url_path      = parse_url( $url, PHP_URL_PATH );
     1062            if ( substr( $url_path, -4 ) == '.zip' || substr( $url_path, -7 ) == '.tar.gz' ) {
     1063                $signature_url = str_replace( $url_path, $url_path . '.sig', $url );
     1064            }
     1065
     1066            /**
     1067             * Filter the URL where the signature for a file is located.
     1068             *
     1069             * @since 5.2
     1070             *
     1071             * @param false|string $signature_url The URL where signatures can be found for a file, or false if none are known.
     1072             * @param string $url                 The URL being verified.
     1073             */
     1074            $signature_url = apply_filters( 'wp_signature_url', $signature_url, $url );
     1075
     1076            if ( $signature_url ) {
     1077                $signature_request = wp_safe_remote_get(
     1078                    $signature_url,
     1079                    array(
     1080                        'limit_response_size' => 10 * 1024, // 10KB should be large enough for quite a few signatures.
     1081                    )
     1082                );
     1083
     1084                if ( ! is_wp_error( $signature_request ) && 200 === wp_remote_retrieve_response_code( $signature_request ) ) {
     1085                    $signature = explode( "\n", wp_remote_retrieve_body( $signature_request ) );
     1086                }
    10591087            }
    10601088        }
     
    10761104             * @param string $url                The url being accessed.
    10771105             */
    1078             apply_filters( 'wp_signature_softfail', $signature_softfail, $url )
     1106            apply_filters( 'wp_signature_softfail', true, $url )
    10791107        ) {
    10801108            $signature_verification->add_data( $tmpfname, 'softfail-filename' );
     
    11461174            ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) ? 'sodium_crypto_sign_verify_detached' : 'sha384' )
    11471175        );
     1176    }
     1177
     1178    // Check for a edge-case affecting PHP Maths abilities
     1179    if (
     1180        ! extension_loaded( 'sodium' ) &&
     1181        in_array( PHP_VERSION_ID, [ 70200, 70201, 70202 ], true ) &&
     1182        extension_loaded( 'opcache' )
     1183    ) {
     1184        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
     1185        // https://bugs.php.net/bug.php?id=75938
     1186
     1187        return new WP_Error(
     1188            'signature_verification_unsupported',
     1189            sprintf(
     1190                /* translators: 1: The filename of the package. */
     1191                __( 'The authenticity of %1$s could not be verified as signature verification is unavailable on this system.' ),
     1192                '<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
     1193            ),
     1194            array(
     1195                'php'    => phpversion(),
     1196                'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
     1197            )
     1198        );
     1199
    11481200    }
    11491201
Note: See TracChangeset for help on using the changeset viewer.