Beispiel #1
0
 /**
  * @param array $args
  * @param callable $transform
  * @return \Amp\Promise
  */
 public function send(array $args, callable $transform = null)
 {
     $promisor = new \Amp\Deferred();
     $this->promisors[] = $promisor;
     $this->getConnection()->send($args);
     return \Amp\pipe($promisor->promise(), function ($response) {
         return $this->parser->parse($response);
     });
 }
Beispiel #2
0
 private function establish()
 {
     \Amp\pipe(\Amp\file\get($this->path), 'Amp\\Socket\\connect')->when(function ($e, $sock) {
         if ($e) {
             $this->failAll();
             return;
         }
         $this->sock = $sock;
         $this->writeWatcher = \Amp\onWritable($sock, $this->writer);
     });
 }
Beispiel #3
0
 private function establish()
 {
     $unix = in_array("unix", \stream_get_transports(), true);
     if ($unix) {
         $promise = \Amp\Socket\connect("unix://{$this->path}.sock");
     } else {
         $promise = \Amp\pipe(\Amp\file\get($this->path), 'Amp\\Socket\\connect');
     }
     $promise->when(function ($e, $sock) {
         if ($e) {
             $this->failAll();
             return;
         }
         $this->sock = $sock;
         $this->writeWatcher = \Amp\onWritable($sock, $this->writer);
     });
 }
Beispiel #4
0
 private function getResourceUri($resource)
 {
     if (!is_string($resource)) {
         throw new InvalidArgumentException(sprintf("\$resource must be of type string, %s given.", gettype($resource)));
     }
     if (substr($resource, 0, 8) === "https://") {
         return new Success($resource);
     }
     if (!$this->dictionary) {
         return \Amp\pipe(\Amp\resolve($this->fetchDictionary()), function () use($resource) {
             return $this->getResourceUri($resource);
         });
     }
     if (isset($this->dictionary[$resource])) {
         return new Success($this->dictionary[$resource]);
     }
     return new Failure(new AcmeException("Resource not found in directory: '{$resource}'."));
 }
Beispiel #5
0
/**
 * Enable encryption on an existing socket stream
 *
 * @param resource $socket
 * @param array $options
 * @return \Amp\Promise
 */
function cryptoEnable($socket, array $options = [])
{
    static $caBundleFiles = [];
    $isLegacy = PHP_VERSION_ID < 50600;
    if ($isLegacy) {
        // For pre-5.6 we always manually verify names in userland
        // using the captured peer certificate.
        $options["capture_peer_cert"] = true;
        $options["verify_peer"] = isset($options["verify_peer"]) ? $options["verify_peer"] : true;
        if (isset($options["CN_match"])) {
            $peerName = $options["CN_match"];
            $options["peer_name"] = $peerName;
            unset($options["CN_match"]);
        }
        if (empty($options["cafile"])) {
            $options["cafile"] = __DIR__ . "/../var/ca-bundle.crt";
        }
    }
    // Externalize any bundle inside a Phar, because OpenSSL doesn't support the stream wrapper.
    if (!empty($options["cafile"]) && strpos($options["cafile"], "phar://") === 0) {
        // Yes, this is blocking but way better than just an error.
        if (!isset($caBundleFiles[$options["cafile"]])) {
            $bundleContent = file_get_contents($options["cafile"]);
            $caBundleFile = tempnam(sys_get_temp_dir(), "openssl-ca-bundle-");
            file_put_contents($caBundleFile, $bundleContent);
            register_shutdown_function(function () use($caBundleFile) {
                @unlink($caBundleFile);
            });
            $caBundleFiles[$options["cafile"]] = $caBundleFile;
        }
        $options["cafile"] = $caBundleFiles[$options["cafile"]];
    }
    if (empty($options["ciphers"])) {
        // See https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
        // DES ciphers have been explicitly removed from that list
        // TODO: We're using the recommended settings for servers here, we need a good resource for clients.
        // Then we might be able to use a more restrictive list.
        // The following cipher suites have been explicitly disabled, taken from previous configuration:
        // !aNULL:!eNULL:!EXPORT:!DES:!DSS:!3DES:!MD5:!PSK
        $options["ciphers"] = \implode(':', ["ECDHE-ECDSA-CHACHA20-POLY1305", "ECDHE-RSA-CHACHA20-POLY1305", "ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-GCM-SHA384", "DHE-RSA-AES128-GCM-SHA256", "DHE-RSA-AES256-GCM-SHA384", "ECDHE-ECDSA-AES128-SHA256", "ECDHE-RSA-AES128-SHA256", "ECDHE-ECDSA-AES128-SHA", "ECDHE-RSA-AES256-SHA384", "ECDHE-RSA-AES128-SHA", "ECDHE-ECDSA-AES256-SHA384", "ECDHE-ECDSA-AES256-SHA", "ECDHE-RSA-AES256-SHA", "DHE-RSA-AES128-SHA256", "DHE-RSA-AES128-SHA", "DHE-RSA-AES256-SHA256", "DHE-RSA-AES256-SHA", "AES128-GCM-SHA256", "AES256-GCM-SHA384", "AES128-SHA256", "AES256-SHA256", "AES128-SHA", "AES256-SHA", "!aNULL", "!eNULL", "!EXPORT", "!DES", "!DSS", "!3DES", "!MD5", "!PSK"]);
    }
    $ctx = \stream_context_get_options($socket);
    if (!empty($ctx['ssl'])) {
        $ctx = $ctx['ssl'];
        $compare = $options;
        $no_SNI_nb_hack = empty($ctx['SNI_nb_hack']);
        unset($ctx['SNI_nb_hack'], $ctx['peer_certificate'], $ctx['SNI_server_name']);
        unset($compare['SNI_nb_hack'], $compare['peer_certificate'], $compare['SNI_server_name']);
        if ($ctx == $compare) {
            return new Success($socket);
        } elseif ($no_SNI_nb_hack) {
            return \Amp\pipe(cryptoDisable($socket), function ($socket) use($options) {
                return cryptoEnable($socket, $options);
            });
        }
    }
    if (isset($options["crypto_method"])) {
        $method = $options["crypto_method"];
        unset($options["crypto_method"]);
    } elseif (PHP_VERSION_ID >= 50600 && PHP_VERSION_ID <= 50606) {
        /** @link https://bugs.php.net/69195 */
        $method = \STREAM_CRYPTO_METHOD_TLS_CLIENT;
    } else {
        // note that this constant actually means "Any TLS version EXCEPT SSL v2 and v3"
        $method = \STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
    }
    $options["SNI_nb_hack"] = false;
    \stream_context_set_option($socket, ["ssl" => $options]);
    return $isLegacy ? \Amp\resolve(__watchCryptoLegacy($method, $socket)) : __watchCrypto($method, $socket);
}
Beispiel #6
0
 /**
  * @param array $strings
  * @return Promise
  */
 public function send(array $strings)
 {
     return \Amp\pipe($this->connect(), function () use($strings) {
         $payload = $this->parsePayload($strings);
         $this->outputBuffer .= $payload;
         $this->outputBufferLength += strlen($payload);
         if ($this->reader !== null) {
             \Amp\enable($this->reader);
         }
         if ($this->writer !== null) {
             \Amp\enable($this->writer);
         }
     });
 }
Beispiel #7
0
function __recurseWithHosts($name, array $types, $options)
{
    // Check for hosts file matches
    if (!isset($options["hosts"]) || $options["hosts"]) {
        static $hosts = null;
        if ($hosts === null || !empty($options["reload_hosts"])) {
            return \Amp\pipe(\Amp\resolve(__loadHostsFile()), function ($value) use(&$hosts, $name, $types, $options) {
                unset($options["reload_hosts"]);
                // avoid recursion
                $hosts = $value;
                return __recurseWithHosts($name, $types, $options);
            });
        }
        $result = [];
        if (in_array(Record::A, $types) && isset($hosts[Record::A][$name])) {
            $result[Record::A] = [[$hosts[Record::A][$name], Record::A, $ttl = null]];
        }
        if (in_array(Record::AAAA, $types) && isset($hosts[Record::AAAA][$name])) {
            $result[Record::AAAA] = [[$hosts[Record::AAAA][$name], Record::AAAA, $ttl = null]];
        }
        if ($result) {
            return new Success($result);
        }
    }
    return \Amp\resolve(__doRecurse($name, $types, $options));
}
Beispiel #8
0
 private function doRequest($uri, $name, $type)
 {
     $server = $this->loadExistingServer($uri) ?: $this->loadNewServer($uri);
     $useTCP = substr($uri, 0, 6) == "tcp://";
     if ($useTCP && isset($server->connect)) {
         return \Amp\pipe($server->connect, function () use($uri, $name, $type) {
             return $this->doRequest($uri, $name, $type);
         });
     }
     // Get the next available request ID
     do {
         $requestId = $this->requestIdCounter++;
         if ($this->requestIdCounter >= MAX_REQUEST_ID) {
             $this->requestIdCounter = 1;
         }
     } while (isset($this->pendingRequests[$requestId]));
     // Create question record
     $question = $this->questionFactory->create($type);
     $question->setName($name);
     // Create request message
     $request = $this->messageFactory->create(MessageTypes::QUERY);
     $request->getQuestionRecords()->add($question);
     $request->isRecursionDesired(true);
     $request->setID($requestId);
     // Encode request message
     $requestPacket = $this->encoder->encode($request);
     if ($useTCP) {
         $requestPacket = pack("n", strlen($requestPacket)) . $requestPacket;
     }
     // Send request
     $bytesWritten = \fwrite($server->socket, $requestPacket);
     if ($bytesWritten === false || isset($packet[$bytesWritten])) {
         throw new ResolutionException("Request send failed");
     }
     $promisor = new Deferred();
     $server->pendingRequests[$requestId] = true;
     $this->pendingRequests[$requestId] = [$promisor, $name, $type, $uri];
     return $promisor->promise();
 }
Beispiel #9
0
/**
 * Enable encryption on an existing socket stream
 *
 * @param resource $socket
 * @param array $options
 * @return \Amp\Promise
 */
function cryptoEnable($socket, array $options = [])
{
    $isLegacy = PHP_VERSION_ID < 50600;
    if ($isLegacy) {
        // For pre-5.6 we always manually verify names in userland
        // using the captured peer certificate.
        $options["capture_peer_cert"] = true;
        $options["verify_peer"] = isset($options["verify_peer"]) ? $options["verify_peer"] : true;
        if (isset($options["CN_match"])) {
            $peerName = $options["CN_match"];
            $options["peer_name"] = $peerName;
            unset($options["CN_match"]);
        }
        if (empty($options["cafile"])) {
            $options["cafile"] = __DIR__ . "/../var/ca-bundle.crt";
        }
    }
    if (empty($options["ciphers"])) {
        $options["ciphers"] = \implode(':', ["ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384", "DHE-RSA-AES128-GCM-SHA256", "DHE-DSS-AES128-GCM-SHA256", "kEDH+AESGCM", "ECDHE-RSA-AES128-SHA256", "ECDHE-ECDSA-AES128-SHA256", "ECDHE-RSA-AES128-SHA", "ECDHE-ECDSA-AES128-SHA", "ECDHE-RSA-AES256-SHA384", "ECDHE-ECDSA-AES256-SHA384", "ECDHE-RSA-AES256-SHA", "ECDHE-ECDSA-AES256-SHA", "DHE-RSA-AES128-SHA256", "DHE-RSA-AES128-SHA", "DHE-DSS-AES128-SHA256", "DHE-RSA-AES256-SHA256", "DHE-DSS-AES256-SHA", "DHE-RSA-AES256-SHA", "AES128-GCM-SHA256", "AES256-GCM-SHA384", "ECDHE-RSA-RC4-SHA", "ECDHE-ECDSA-RC4-SHA", "AES128", "AES256", "RC4-SHA", "HIGH", "!aNULL", "!eNULL", "!EXPORT", "!DES", "!3DES", "!MD5", "!PSK"]);
    }
    $ctx = \stream_context_get_options($socket);
    if (!empty($ctx['ssl'])) {
        $ctx = $ctx['ssl'];
        $compare = $options;
        $no_SNI_nb_hack = empty($ctx['SNI_nb_hack']);
        unset($ctx['SNI_nb_hack'], $ctx['peer_certificate'], $ctx['SNI_server_name']);
        unset($compare['SNI_nb_hack'], $compare['peer_certificate'], $compare['SNI_server_name']);
        if ($ctx == $compare) {
            return new Success($socket);
        } elseif ($no_SNI_nb_hack) {
            return \Amp\pipe(cryptoDisable($socket), function ($socket) use($options) {
                return cryptoEnable($socket, $options);
            });
        }
    }
    if (isset($options["crypto_method"])) {
        $method = $options["crypto_method"];
        unset($options["crypto_method"]);
    } elseif (PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50606) {
        $method = \STREAM_CRYPTO_METHOD_TLS_CLIENT;
    } else {
        $method = \STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
    }
    $options["SNI_nb_hack"] = false;
    \stream_context_set_option($socket, ["ssl" => $options]);
    return $isLegacy ? \Amp\resolve(__watchCryptoLegacy($method, $socket)) : __watchCrypto($method, $socket);
}