forked from zer.ooo/web
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
4.3 KiB
PHP
128 lines
4.3 KiB
PHP
<?php
|
|
namespace Eater\Glim\Service;
|
|
|
|
|
|
use Eater\Glim\Model\Server as ServerModel;
|
|
use GuzzleHttp\Client as HttpClient;
|
|
use Eater\Glim\Core;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
class Server extends Main
|
|
{
|
|
const MANAGEMENT_PORT = 7864;
|
|
|
|
private $httpClient = null;
|
|
|
|
private function getHttpClient() {
|
|
if ($this->httpClient === null) {
|
|
$this->httpClient = new HttpClient();
|
|
}
|
|
|
|
return $this->httpClient;
|
|
}
|
|
|
|
public function getCsrFromServer(ServerModel $server) {
|
|
$response = $this->doSignedRequest($server, '/create-csr', [
|
|
'hostname' => $server->getFqdn()
|
|
]);
|
|
|
|
if ($response->getStatusCode() !== 200) {
|
|
throw new \Exception('Requesting CSR failed (' . $response->getStatusCode() . '): ' . $response->getBody()->getContents());
|
|
}
|
|
|
|
$data = $this->decryptResponse($server, $response);
|
|
|
|
return $data['csr'];
|
|
}
|
|
|
|
/**
|
|
* @param ServerModel $server
|
|
* @throws \Exception
|
|
*/
|
|
public function deliverSignedCertificate(ServerModel $server) {
|
|
$response = $this->doSignedRequest($server, '/deliver-crt', [
|
|
'certificate' => $server->getCertificate()
|
|
]);
|
|
|
|
if ($response->getStatusCode() !== 200) {
|
|
throw new \Exception('Delivering signed certificate failed (' . $response->getStatusCode() . '): ' . $response->getBody()->getContents());
|
|
}
|
|
|
|
$server->setStatus('signed');
|
|
$server->save();
|
|
}
|
|
|
|
|
|
public function deliverOpenVPNConfig(ServerModel $server) {
|
|
/** @var \Twig_Environment $twig */
|
|
$twig = $this->get('twig');
|
|
$config = $twig->render('etc/openvpn-server.conf.twig', [
|
|
'server' => $server
|
|
]);
|
|
|
|
$response = $this->doSignedRequest($server, '/update-openvpn-config', [
|
|
'config' => $config
|
|
]);
|
|
|
|
if ($response->getStatusCode() !== 200) {
|
|
throw new \Exception('Updating openvpn server config failed (' . $response->getStatusCode() . '): ' . $response->getBody()->getContents());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param ServerModel $server
|
|
* @param string $path
|
|
* @param string $data
|
|
* @return \Psr\Http\Message\ResponseInterface
|
|
* @throws \Exception
|
|
*/
|
|
public function doSignedRequest(ServerModel $server, $path, $data) {
|
|
$client = $this->getHttpClient();
|
|
|
|
/** @var CA $ca */
|
|
$ca = $this->get('ca');
|
|
|
|
$data['signature'] = bin2hex($ca->signWithCA($server->getFingerprint()));
|
|
|
|
$json = json_encode($data);
|
|
|
|
$password = bin2hex(openssl_random_pseudo_bytes(48));
|
|
$pubKey = openssl_get_publickey($server->getPublicKey());
|
|
$success = openssl_public_encrypt($password, $crypted, $pubKey, OPENSSL_PKCS1_PADDING);
|
|
|
|
if (!$success) {
|
|
throw new \Exception('Encrypting data failed: ' . openssl_error_string() . openssl_error_string());
|
|
}
|
|
|
|
$body = bin2hex($crypted) . bin2hex(openssl_encrypt($json, 'blowfish', substr($password, 0, 32), true, substr($password, 32, 8)));
|
|
return $client->post('http://' . $server->getExternalIp() . ':' . static::MANAGEMENT_PORT . $path, [
|
|
'body' => $body
|
|
]);
|
|
}
|
|
|
|
public function decryptResponse(ServerModel $server, ResponseInterface $response) {
|
|
$body = $response->getBody()->getContents();
|
|
$this->get('logger')->addDebug($body);
|
|
$encryptedPasswordAndIV = hex2bin(substr($body, 0, 512));
|
|
$encryptedBody = hex2bin(substr($body, 512));
|
|
|
|
/** @var CA $ca */
|
|
$ca = $this->get('ca');
|
|
|
|
$success = openssl_private_decrypt($encryptedPasswordAndIV, $passwordAndIV, $ca->getPrivateKey(), OPENSSL_PKCS1_PADDING);
|
|
if (!$success) {
|
|
throw new \Exception('Decrypting data failed: ' . openssl_error_string() . openssl_error_string());
|
|
}
|
|
|
|
$json = openssl_decrypt($encryptedBody, 'blowfish', substr($passwordAndIV, 0, 32), true, substr($passwordAndIV, 32, 8));
|
|
$data = \json_decode($json, true);
|
|
$ver = openssl_verify($server->getFingerprint(), hex2bin($data['signature']), $server->getPublicKey(), OPENSSL_ALGO_SHA256);
|
|
|
|
if ($ver === 1) {
|
|
return $data;
|
|
} else {
|
|
throw new \Exception("Checking signature failed ($ver): " . openssl_error_string());
|
|
}
|
|
}
|
|
}
|