Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TLS Client Certificates #377

Open
pbiron opened this issue Jan 30, 2020 · 2 comments
Open

Support TLS Client Certificates #377

pbiron opened this issue Jan 30, 2020 · 2 comments

Comments

@pbiron
Copy link

pbiron commented Jan 30, 2020

Per the suggestion in https://core.trac.wordpress.org/ticket/34883#comment:3, I'm opening this issue so that WP's wp_remote_request(), etc can more easily use client certs.

And while not mentioned in the Trac ticket, there is also need to set CURLOPT_SSLKEY.

@qwqoffice
Copy link

Needs 4 options:

CURLOPT_SSLCERTTYPE
CURLOPT_SSLCERT
CURLOPT_SSLKEYTYPE
CURLOPT_SSLKEY

Otherwise I can only use native cURL instead of wp_remote_request

@remcotolsma
Copy link

remcotolsma commented May 8, 2024

We did some research @pronamic and this can perhaps be simplified to 3 options for now:

cURL Streams WordPress Description
CURLOPT_SSLCERTTYPE Not available, PEM required. Always require PEM in the WordPress requests library?
CURLOPT_SSLCERT local_cert ssl_certificate
CURLOPT_SSLKEYTYPE Not available, PEM required. Always require PEM in the WordPress requests library?
CURLOPT_SSLKEY local_pk ssl_private_key
CURLOPT_SSLKEYPASSWD passphrase ssl_private_key_password
CURLOPT_SSLCERTPASSWD Not available. It is not common practice to protect certificate files with a password?
CURLOPT_CAINFO 'ssl' => 'cafile' sslcertificates Rename to ssl_ca_file?
CURLOPT_SSL_VERIFYPEER 'ssl' => 'verify_peer' sslverify Rename to ssl_verify_peer?

In the request arguments we could perhaps use the following naming convention:

  • ssl_certificate
  • ssl_private_key
  • ssl_private_key_password

For the cURL transport support for this can be added like this:

/**
 * Support TLS Client Certificates.
 * 
 * @link https://core.trac.wordpress.org/ticket/34883#comment:3
 * @link https://github.com/WordPress/Requests/issues/377
 */
\add_action(
	'http_api_curl',
	function ( $handle, $parsed_args, $url ) {
		if ( \array_key_exists( 'ssl_certificate', $parsed_args ) ) {
			\curl_setopt( $handle, \CURLOPT_SSLCERT, $parsed_args['ssl_certificate'] );		
		}

		if ( \array_key_exists( 'ssl_private_key', $parsed_args ) ) {
			\curl_setopt( $handle, \CURLOPT_SSLKEY, $parsed_args['ssl_private_key'] );		
		}

		if ( \array_key_exists( 'ssl_private_key_password', $parsed_args ) ) {
			\curl_setopt( $handle, \CURLOPT_SSLKEYPASSWD, $parsed_args['ssl_private_key_password'] );		
		}
	},
	10,
	3
);

It looks like there are currently no hooks available for the streams transport context:

$host = $url_parts['host'];
$context = stream_context_create();
$verifyname = false;
$case_insensitive_headers = new CaseInsensitiveDictionary($headers);
// HTTPS support
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
$remote_socket = 'ssl://' . $host;
if (!isset($url_parts['port'])) {
$url_parts['port'] = Port::HTTPS;
}
$context_options = [
'verify_peer' => true,
'capture_peer_cert' => true,
];
$verifyname = true;
// SNI, if enabled (OpenSSL >=0.9.8j)
// phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound
if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
$context_options['SNI_enabled'] = true;
}
if (isset($options['verify'])) {
if ($options['verify'] === false) {
$context_options['verify_peer'] = false;
$context_options['verify_peer_name'] = false;
$verifyname = false;
} elseif (is_string($options['verify'])) {
$context_options['cafile'] = $options['verify'];
}
}
if (isset($options['verifyname']) && $options['verifyname'] === false) {
$context_options['verify_peer_name'] = false;
$verifyname = false;
}
// Handle the PHP 8.4 deprecation (PHP 9.0 removal) of the function signature we use for stream_context_set_option().
// Ref: https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#stream_context_set_option
if (function_exists('stream_context_set_options')) {
// PHP 8.3+.
stream_context_set_options($context, ['ssl' => $context_options]);
} else {
// PHP < 8.3.
stream_context_set_option($context, ['ssl' => $context_options]);
}
} else {
$remote_socket = 'tcp://' . $host;
}
$this->max_bytes = $options['max_bytes'];
if (!isset($url_parts['port'])) {
$url_parts['port'] = Port::HTTP;
}
$remote_socket .= ':' . $url_parts['port'];
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE);
$options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]);
$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants