There is also a crypto_type context. In older versions this was crypto_method. This is referenced on http://php.net/manual/en/function.stream-socket-enable-crypto.php.
SSL context options — SSL context option listing
Context options for ssl:// and tls:// transports.
| Version | Description |
|---|---|
| 5.6.0 |
Added peer_fingerprint and verify_peer_name.
verify_peer default changed to TRUE.
|
| 5.4.13 |
Added disable_compression. Requires OpenSSL >= 1.0.0.
|
| 5.3.2 |
Added SNI_enabled and
SNI_server_name.
|
Note: Because ssl:// is the underlying transport for the https:// and ftps:// wrappers, any context options which apply to ssl:// also apply to https:// and ftps://.
Note: For SNI (Server Name Indication) to be available, then PHP must be compiled with OpenSSL 0.9.8j or greater. Use the
OPENSSL_TLSEXT_SERVER_NAMEto determine whether SNI is supported.
There is also a crypto_type context. In older versions this was crypto_method. This is referenced on http://php.net/manual/en/function.stream-socket-enable-crypto.php.
CN_match works contrary to intuitive thinking. I came across this when I was developing SSL server implemented in PHP. I stated (in code):
- do not allow self signed certs (works)
- verify peer certs against CA cert (works)
- verify the client's CN against CN_match (does not work), like this:
stream_context_set_option($context, 'ssl', 'CN_match', '*.example.org');
I presumed this would match any client with CN below .example.org domain.
Unfortunately this is NOT the case. The option above does not do that.
What it really does is this:
- it takes client's CN and compares it to CN_match
- IF CLIENT's CN CONTAINS AN ASTERISK like *.example.org, then it is matched against CN_match in wildcard matching fashion
Examples to illustrate behaviour:
(CNM = server's CN_match)
(CCN = client's CN)
- CNM=host.example.org, CCN=host.example.org ---> OK
- CNM=host.example.org, CCN=*.example.org ---> OK
- CNM=.example.org, CCN=*.example.org ---> OK
- CNM=example.org, CCN=*.example.org ---> ERROR
- CNM=*.example.org, CCN=host.example.org ---> ERROR
- CNM=*.example.org, CCN=*.example.org ---> OK
According to PHP sources I believe that the same applies if you are trying to act as Client and the server contains a wildcard certificate. If you set CN_match to myserver.example.org and server presents itself with *.example.org, the connection is allowed.
Everything above applies to PHP version 5.2.12.
I will supply a patch to support CN_match starting with asterisk.
I am unable to load a PEM that was generated with the stunnel tools. However, I am able to use PHP calls to generate a working PEM that is recognized both by stunnel and php, as outlined here:
http://www.devdungeon.com/content/how-use-ssl-sockets-php
This code fragment is now working for me, and with stunnel verify=4, both sides confirm the fingerprint. Oddly, if "tls://" is set below, then TLSv1 is forced, but using "ssl://" allows TLSv1.2:
$stream_context = stream_context_create([ 'ssl' => [
'local_cert' => '/path/to/key.pem',
'peer_fingerprint' => openssl_x509_fingerprint(file_get_contents('/path/to/key.crt')),
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
'verify_depth' => 0 ]]);
$fp = stream_socket_client('ssl://ssl.server.com:12345',
$errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream_context);
fwrite($fp, "foo bar\n");
while($line = fgets($fp, 8192)) echo $line;
It appears that "allow_self_signed" does not and cannot apply to the local_cert option.
The stunnel verify=4 option, which verifies but ignores a CA, has no analog in these settings, which is unfortunate.
Even more perplexingly, while the "openssl verify -CAfile" is successful, PHP appears unable to use the new ca/crt pair in any configuration.
I did actually link my PHP against a copy of LibreSSL 2.3.8, but PHP oddly is unable to use TLS1.1 or 1.2. It does, however, enable EC secp521r1 (of which my native OpenSSL 0.9.8e is incapable).
I used this for Apple Push Notification Service.
Passed in a local certificate filename `cert.pem` trough local_cert option.
Worked fine, when invoked the script directly.
But when I included/required the script from a different location, it stopped working, without any explicit error message.
Resolved by passed in the full path for the file `<FullPathTo>cert.pem`.