Ejemplo n.º 1
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $error = $output->getErrorOutput();
     $path = $input->getArgument("path");
     $includeRoot = $input->getOption("include-root");
     if (!\file_exists($path)) {
         throw new \Exception("File {$path} doesn't exist");
     }
     try {
         list($inform, $format) = \detectCertFormat($path);
         $cert = \parseFormattedCert(\readCertificate($path, $inform, $format));
     } catch (\Exception $e) {
         $err = implode("\n", $e->output);
         throw new \Exception("Unable to load certificate: {$err}");
     }
     // perform some basic checks
     if (\isExpired($cert)) {
         $error->writeln("Certificate has expired");
     }
     if (\areCertsLinked($cert, $cert)) {
         throw new \Exception("Self-signed or CA cert");
     }
     // this can fail with an exception
     $out = \buildChain($cert, $path, $includeRoot);
     $output->write($out);
 }
Ejemplo n.º 2
0
function buildChain($cert, $certPath, $includeRoot = false)
{
    if (isExpired($cert)) {
        throw new Exception("Certificate has expired");
    }
    if (areCertsLinked($cert, $cert)) {
        throw new Exception("Self-signed or CA cert");
    }
    $uris = $cert["issuers"];
    if (!$uris) {
        throw new Exception("Certificate doesn't specify issuers");
    }
    $c = $cert;
    $chain = [];
    while (sizeof($uris) > 0) {
        $old = $c;
        $uri = array_shift($uris);
        $path = downloadIssuer($uri);
        list($inform, $format) = detectCertFormat($path);
        $c = parseFormattedCert(readCertificate($path, $inform, $format));
        if (isExpired($c)) {
            throw new Exception("Expired intermediate in the chain");
        }
        if (areCertsLinked($c, $c)) {
            break;
        }
        if (!areCertsLinked($c, $old)) {
            $msg = "Intermediate doesn't match previous certificate in the chain";
            throw new Exception($msg);
        }
        $chain[] = $path;
        if (isset($c["issuers"])) {
            foreach ($c["issuers"] as $i) {
                $uris[] = $i;
                // we don't currently have a good way of handling multiple
                // issuers
                break;
            }
        }
    }
    // we are at the end of the chain, see if there's matching root CA
    $cacheDir = __DIR__ . '/cache';
    $adapter = new File($cacheDir);
    $adapter->setOption('ttl', 600);
    $cache = new Cache($adapter);
    if (!$cache->get(md5($path) . "-root")) {
        $root = findMatchingRoot($c);
        $chain[] = $root;
        $cache->set(md5($path) . "-root", $root);
    } else {
        $chain[] = $cache->get(md5($path) . "-root");
    }
    // build certificate bundle
    foreach ($chain as $i => $path) {
        list($inform, $format) = detectCertFormat($path);
        $cmd = sprintf("openssl x509 -inform %s -outform pem -in %s -out %s", escapeshellarg($inform), escapeshellarg($path), escapeshellarg(__DIR__ . "/tmp/" . sha1($cert["subject"]) . "-{$i}.pem"));
        exec($cmd);
    }
    unlink(__DIR__ . "/tmp/bundle.crt");
    foreach ($chain as $i => $path) {
        file_put_contents(__DIR__ . "/tmp/bundle.crt", file_get_contents(__DIR__ . "/tmp/" . sha1($cert["subject"]) . "-{$i}.pem"), FILE_APPEND);
    }
    // verify the chain is valid
    $cmd = sprintf("openssl verify -verbose -purpose sslserver -CAfile %s/tmp/bundle.crt %s", __DIR__, escapeshellarg($certPath));
    try {
        execute($cmd);
    } catch (Exception $e) {
        $err = implode("\n", $e->output);
        throw new Exception("Can't verify the bundle: {$err}");
    }
    // extract the original cert (it might contain some, or all, parts of the
    // chain already)
    $cmd = sprintf("openssl x509 -inform pem -outform pem -in %s", $certPath);
    $out = implode("\n", execute($cmd));
    $out .= "\n";
    if (!$includeRoot) {
        array_pop($chain);
    }
    foreach ($chain as $i => $path) {
        $out .= file_get_contents(__DIR__ . "/tmp/" . sha1($cert["subject"]) . "-{$i}.pem");
        unlink(__DIR__ . "/tmp/" . sha1($cert["subject"]) . "-{$i}.pem");
    }
    return $out;
}