예제 #1
0
 /**
  * Get/verify/parse a JSON response
  *
  * The _server_ is the one that signs the message.
  * We're just verifying the Ed25519 signature.
  *
  * @param string $url
  * @param SignaturePublicKey $publicKey
  * @param array $args
  * @param array $options
  * @return array
  * @throws \Exception
  */
 public static function postSignedJSON(string $url, SignaturePublicKey $publicKey, array $args = [], array $options = []) : array
 {
     $body = self::post($url, $args, $options);
     if (empty($body)) {
         throw new \Exception('Empty response from ' . $url);
     }
     if (self::$debug) {
         \var_dump($body);
     }
     $firstNewLine = \strpos($body, "\n");
     // There should be a newline immediately after the base64urlsafe-encoded signature
     if ($firstNewLine !== self::ENCODED_SIGNATURE_LENGTH) {
         throw new \Exception('Invalid Signature');
     }
     $sig = Base64UrlSafe::decode(Binary::safeSubstr($body, 0, self::ENCODED_SIGNATURE_LENGTH));
     $msg = Binary::safeSubstr($body, self::ENCODED_SIGNATURE_LENGTH + 1);
     if (!Asymmetric::verify($msg, $publicKey, $sig, true)) {
         throw new \Exception('Invalid Signature');
     }
     return \json_decode($msg, true);
 }
예제 #2
0
파일: Hail.php 프로젝트: paragonie/airship
 /**
  * Parse a signed JSON response
  *
  * @param Response $response
  * @param SignaturePublicKey $publicKey
  * @return mixed
  * @throws SignatureFailed
  * @throws TransferException
  */
 public function parseSignedJSON(Response $response, SignaturePublicKey $publicKey)
 {
     $code = $response->getStatusCode();
     if ($code >= 200 && $code < 300) {
         $body = (string) $response->getBody();
         $firstNewLine = \strpos($body, "\n");
         // There should be a newline immediately after the base64urlsafe-encoded signature
         if ($firstNewLine !== self::ENCODED_SIGNATURE_LENGTH) {
             throw new SignatureFailed(\sprintf("First newline found at position %s, expected %d.\n%s", \print_r($firstNewLine, true), \print_r(self::ENCODED_SIGNATURE_LENGTH, true), Base64::encode($body)));
         }
         $sig = Base64UrlSafe::decode(Binary::safeSubstr($body, 0, 88));
         $msg = Binary::safeSubstr($body, 89);
         if (!Asymmetric::verify($msg, $publicKey, $sig, true)) {
             throw new SignatureFailed();
         }
         return \Airship\parseJSON($msg, true);
     }
     throw new TransferException();
 }
예제 #3
0
 /**
  * Parse the HTTP response and get the useful information out of it.
  *
  * @param array $data
  * @param \DateTime $originated
  * @return array
  * @throws CouldNotUpdate
  */
 protected function parseChannelUpdateResponse(array $data, \DateTime $originated) : array
 {
     if ($data['status'] !== 'success') {
         throw new CouldNotUpdate($data['message'] ?? \__('An update error has occurred'));
     }
     $valid = [];
     if (!empty($data['no_updates'])) {
         // Verify signature of the "no updates" timestamp.
         $sig = Base64UrlSafe::decode($data['signature']);
         if (!AsymmetricCrypto::verify($data['no_updates'], $this->channelPublicKey, $sig, true)) {
             throw new CouldNotUpdate(\__('Invalid signature from channel'));
         }
         $time = (new \DateTime($data['no_updates']))->add(new \DateInterval('P01D'));
         if ($time < $originated) {
             throw new CouldNotUpdate(\__('Channel is reporting a stale "no update" status'));
         }
         // No updates.
         return [];
     }
     // Verify the signature of each update.
     foreach ($data['updates'] as $update) {
         $data = Base64UrlSafe::decode($update['data']);
         $sig = Base64UrlSafe::decode($update['signature']);
         if (AsymmetricCrypto::verify($data, $this->channelPublicKey, $sig, true)) {
             $dataInternal = \json_decode($data, true);
             $valid[] = ['id' => (int) $update['id'], 'stored' => $dataInternal['stored'], 'master_signature' => $dataInternal['master_signature'], 'root' => $dataInternal['root'], 'data' => $dataInternal['data']];
         }
     }
     // Sort by ID
     \uasort($valid, function (array $a, array $b) : int {
         return (int) ($a['id'] <=> $b['id']);
     });
     return $valid;
 }
예제 #4
0
 /**
  * RFC 4648 Base64 (URL Safe) decoding
  *
  * "Zm9v" -> "foo"
  *
  * @param string $str
  * @return string
  */
 public function base64UrlSafeDecode(string $str) : string
 {
     return Base64UrlSafe::decode($str, true);
 }