verify_file_signature() │ WP 5.2.0
Проверяет файл по одной или нескольким цифровым подписям Ed25519.
Вычисляет SHA-384-хеш файла и проверяет подписи с помощью доверенных ключей WordPress, полученных через wp_trusted_keys() . Проверка считается успешной, если хотя бы одна подпись подходит хотя бы к одному ключу.
Подписи и доверенные ключи должны быть закодированы в Base64. Подписи и ключи неправильной длины пропускаются.
Функция проверяет подписи только по встроенным доверенным ключам WordPress. Передать собственный открытый ключ нельзя.
Для проверки необходимы алгоритм SHA-384 и нативное расширение Sodium либо достаточно быстрый полифил Sodium_Compat.
1 раз — 0.000417 сек (быстро) | 50000 раз — 1.72 сек (быстро) | PHP 8.2.28, WP 7.0.2
Хуков нет.
Возвращает
true|false|WP_Error.
true - подпись подтверждена.
WP_Error - проверка невозможна, подпись отсутствует или не прошла проверку.
false - указан в официальном описании для случая, когда проверка не выполнялась, но актуальный код функции не возвращает это значение.
Использование
verify_file_signature( $filename, $signatures, $filename_for_errors );
$filename(string) (обязательный)
Путь к проверяемому файлу.
$signatures(string|array) (обязательный)
Одна подпись или массив подписей Ed25519 в формате Base64.
$filename_for_errors(string|false)
Понятное название файла для сообщений об ошибках. Не влияет на путь к проверяемому файлу. При false используется имя файла из $filename.
По умолчанию: false
Примеры
#1 Проверка подписи файла
$result = verify_file_signature(
WP_CONTENT_DIR . '/upgrade/wordpress.zip',
$signature,
'wordpress.zip'
);
if ( is_wp_error( $result ) ) {
wp_die( esc_html( $result->get_error_message() ) );
}
Добавить свой пример
Список изменений
Код verify_file_signature() verify file signature
WP 7.0.2
function verify_file_signature( $filename, $signatures, $filename_for_errors = false ) {
if ( ! $filename_for_errors ) {
$filename_for_errors = wp_basename( $filename );
}
// Check we can process signatures.
if ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) || ! in_array( 'sha384', array_map( 'strtolower', hash_algos() ), true ) ) {
return new WP_Error(
'signature_verification_unsupported',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified as signature verification is unavailable on this system.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
( ! function_exists( 'sodium_crypto_sign_verify_detached' ) ? 'sodium_crypto_sign_verify_detached' : 'sha384' )
);
}
// 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 utilizes during signing verifications.
*/
// phpcs:disable WordPress.NamingConventions.ValidVariableName
$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;
// phpcs:enable
}
/*
* 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: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified as signature verification is unavailable on this system.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
array(
'php' => PHP_VERSION,
'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',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified as no signature was found.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
array(
'filename' => $filename_for_errors,
)
);
}
$trusted_keys = wp_trusted_keys();
$file_hash = hash_file( 'sha384', $filename, true );
mbstring_binary_safe_encoding();
$skipped_key = 0;
$skipped_signature = 0;
foreach ( (array) $signatures as $signature ) {
$signature_raw = base64_decode( $signature );
// Ensure only valid-length signatures are considered.
if ( SODIUM_CRYPTO_SIGN_BYTES !== strlen( $signature_raw ) ) {
++$skipped_signature;
continue;
}
foreach ( (array) $trusted_keys as $key ) {
$key_raw = base64_decode( $key );
// Only pass valid public keys through.
if ( SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen( $key_raw ) ) {
++$skipped_key;
continue;
}
if ( sodium_crypto_sign_verify_detached( $signature_raw, $file_hash, $key_raw ) ) {
reset_mbstring_encoding();
return true;
}
}
}
reset_mbstring_encoding();
return new WP_Error(
'signature_verification_failed',
sprintf(
/* translators: %s: The filename of the package. */
__( 'The authenticity of %s could not be verified.' ),
'<span class="code">' . esc_html( $filename_for_errors ) . '</span>'
),
// Error data helpful for debugging:
array(
'filename' => $filename_for_errors,
'keys' => $trusted_keys,
'signatures' => $signatures,
'hash' => bin2hex( $file_hash ),
'skipped_key' => $skipped_key,
'skipped_sig' => $skipped_signature,
'php' => PHP_VERSION,
'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
)
);
}
Cвязанные функции