extract_signature(); if (is_wp_error($signature)) { self::$auth_result = $signature; return self::$auth_result; } $public_key = $this->load_public_key(); if (is_wp_error($public_key)) { self::$auth_result = $public_key; return self::$auth_result; } $domain = $this->get_normalized_domain(); $result = openssl_verify($domain, $signature, $public_key, OPENSSL_ALGO_SHA256); if ($result !== 1) { self::$auth_result = new WP_Error( 'twokcs_authorization_failed', 'Invalid authorization header', ['status' => 401] ); return self::$auth_result; } self::$auth_result = true; return self::$auth_result; } /** * Extract the base64-encoded signature from the Authorization header. * * @return string|WP_Error Binary signature on success. */ private function extract_signature() { $header = $this->get_authorization_header(); if ($header === null) { return new WP_Error( 'twokcs_authorization_failed', 'Authorization header not found in request', ['status' => 401] ); } $encoded = null; if (stripos($header, Twokcs_Constants::AUTH_SCHEME_TWOKCS . ' ') === 0) { $encoded = substr($header, strlen(Twokcs_Constants::AUTH_SCHEME_TWOKCS . ' ')); } elseif (stripos($header, Twokcs_Constants::AUTH_SCHEME_BASIC . ' ') === 0) { $encoded = substr($header, strlen(Twokcs_Constants::AUTH_SCHEME_BASIC . ' ')); } if ($encoded === null || $encoded === '') { return new WP_Error( 'twokcs_authorization_failed', 'Invalid authorization header format', ['status' => 401] ); } $signature = base64_decode($encoded, true); if ($signature === false) { return new WP_Error( 'twokcs_authorization_failed', 'Failed to decode authorization header', ['status' => 401] ); } return $signature; } /** * Read the Authorization header from server variables. * * @return string|null */ private function get_authorization_header() { if (!empty($_SERVER['HTTP_AUTHORIZATION'])) { return sanitize_text_field(wp_unslash($_SERVER['HTTP_AUTHORIZATION'])); } if (!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { return sanitize_text_field(wp_unslash($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])); } return null; } /** * Load the RSA public key resource. * * @return resource|OpenSSLAsymmetricKey|WP_Error */ private function load_public_key() { $key_path = TWOKCS_PLUGIN_DIR . Twokcs_Constants::PUBLIC_KEY_FILE; if (!is_readable($key_path)) { $message = 'Authentication configuration error'; if (defined('WP_DEBUG') && WP_DEBUG) { $message = 'Public key file is missing or not readable: ' . $key_path; } return new WP_Error( 'twokcs_authorization_failed', $message, ['status' => 500] ); } $public_key = openssl_pkey_get_public(file_get_contents($key_path)); if ($public_key === false) { $message = 'Authentication configuration error'; if (defined('WP_DEBUG') && WP_DEBUG) { $message = 'Failed to extract public key: ' . openssl_error_string(); } return new WP_Error( 'twokcs_authorization_failed', $message, ['status' => 500] ); } return $public_key; } /** * Normalize the store domain for signature verification. * * @return string */ private function get_normalized_domain() { $domain = wp_parse_url(site_url(), PHP_URL_HOST); if (is_string($domain) && substr($domain, 0, 4) === 'www.') { $domain = substr($domain, 4); } return (string) $domain; } }