Skip to content

Commit

Permalink
Reject MD5 and SHA1 certificates
Browse files Browse the repository at this point in the history
Even if https://wiki.php.net/rfc/distrust-sha1-certificates makes it into PHP 7.2, earlier versions will probably still accept SHA1 certificates. We want to provide a secure-by-default socket component, so we reject these manually.
  • Loading branch information
kelunik committed Jul 3, 2017
1 parent e58766b commit 3bbd11c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -34,7 +34,8 @@
"amphp/amp": "^2",
"amphp/dns": "^0.9",
"amphp/byte-stream": "^1.1",
"amphp/uri": "^0.1"
"amphp/uri": "^0.1",
"kelunik/certificate": "^1.1"
},
"require-dev": {
"amphp/phpunit-util": "^1",
Expand Down
26 changes: 26 additions & 0 deletions lib/Internal/functions.php
Expand Up @@ -9,6 +9,7 @@
use Amp\Socket\CryptoException;
use Amp\Success;
use function Amp\call;
use Kelunik\Certificate\Certificate;

/**
* Parse an URI into [scheme, host, port].
Expand Down Expand Up @@ -72,6 +73,9 @@ function parseUri(string $uri): array {
function enableCrypto($socket, array $options = [], bool $force = false): Promise {
$ctx = \stream_context_get_options($socket);

$options["capture_peer_cert"] = true;
$options["capture_peer_cert_chain"] = true;

if (!$force && !empty($ctx['ssl']) && !empty($ctx["ssl"]["_enabled"])) {
$cmp = array_merge($ctx["ssl"], $options["ssl"] ?? []);
$ctx = $ctx['ssl'];
Expand Down Expand Up @@ -140,6 +144,28 @@ function onCryptoWatchReadability($watcherId, $socket, Deferred $deferred) {
// If $result is 0, just wait for the next invocation
if ($result === true) {
Loop::cancel($watcherId);

$options = \stream_context_get_options($socket);

if ($options["ssl"]["verify_peer"] ?? true) {
$certs = array_merge([$options["ssl"]["peer_certificate"]], $options["ssl"]["peer_certificate_chain"]);

foreach ($certs as $cert) {
$cert = new Certificate($cert);

if ($cert->isSelfSigned()) {
// Ignore self-signed certificates, because they don't trust the signature
continue;
}

if (in_array($cert->getSignatureType(), ["md5WithRSAEncryption", "sha1WithRSAEncryption"], true)) {
@\fclose($socket);

$deferred->fail(new CryptoException("The server provided a certificate using a MD5 / SHA1 signature scheme"));
}
}
}

$deferred->resolve();
} elseif ($result === false) {
Loop::cancel($watcherId);
Expand Down

0 comments on commit 3bbd11c

Please sign in to comment.