diff --git a/src/conduit/ConduitClient.php b/src/conduit/ConduitClient.php --- a/src/conduit/ConduitClient.php +++ b/src/conduit/ConduitClient.php @@ -8,6 +8,8 @@ private $timeout = 300.0; private $username; private $password; + private $publicKey; + private $privateKey; public function getConnectionID() { return $this->connectionID; @@ -37,6 +39,15 @@ return $this; } + public function setSigningKeys( + $public_key, + PhutilOpaqueEnvelope $private_key) { + + $this->publicKey = $public_key; + $this->privateKey = $private_key; + return $this; + } + public function callMethod($method, array $params) { $meta = array(); @@ -59,6 +70,16 @@ unset($params['certificate']); } + if ($this->privateKey && $this->publicKey) { + $signature = $this->signSignature( + $method, + $params, + $meta); + + $meta['publicKey'] = $this->publicKey; + $meta['signature'] = $signature; + } + if ($meta) { $params['__conduit__'] = $meta; } @@ -102,4 +123,41 @@ return $this; } + private function signSignature( + $method, + array $params, + array $meta) { + + $signature = ''; + $result = openssl_sign( + self::getEncodedParameters($method, $params, $meta), + $signature, + $this->privateKey->openEnvelope()); + if (!$result) { + throw new Exception('Unable to sign Conduit request with signing key.'); + } + + return base64_encode($signature); + } + + public static function verifySignature( + $signature, + $public_key, + array $method, + array $params, + array $meta) { + + return openssl_verify( + self::getEncodedParameters($method, $params, $meta), + base64_decode($signature), + $public_key) === 1; + } + + private static function getEncodedParameters($method, $params, $meta) { + return json_encode(array( + 'method' => $method, + 'params' => $params, + 'meta' => $meta, + )); + } }