/** * Verify the contents of a file * * @param $input (file handle) * @param SignaturePublicKey $publickey * @param string $signature * @param bool $raw_binary Don't hex encode? * * @return bool */ protected static function verifyData(ReadOnlyFile $input, SignaturePublicKey $publickey, string $signature, bool $raw_binary = false) : bool { $csum = self::checksumData($input, $publickey, true); return AsymmetricCrypto::verify($csum, $publickey, $signature, $raw_binary); }
/** * Interpret the TreeUpdate objects from the API response. OR verify the signature * of the "no updates" message to prevent a DoS. * * Dear future security auditors: This is important. * * @param Channel $chan * @param array $response * @return TreeUpdate[] * @throws ChannelSignatureFailed * @throws CouldNotUpdate */ protected function parseTreeUpdateResponse(Channel $chan, array $response) : array { if (!empty($response['no_updates'])) { // The "no updates" message should be authenticated. $signatureVerified = AsymmetricCrypto::verify($response['no_updates'], $chan->getPublicKey(), Base64UrlSafe::decode($response['signature']), true); if (!$signatureVerified) { throw new ChannelSignatureFailed(); } $datetime = new \DateTime($response['no_updates']); // One day ago: $stale = (new \DateTime('now'))->sub(new \DateInterval('P01D')); if ($datetime < $stale) { throw new CouldNotUpdate(\__('Stale response.')); } // We got nothing to do: return []; } // We were given updates. Let's validate them! $TreeUpdateArray = []; foreach ($response['updates'] as $update) { $data = Base64UrlSafe::decode($update['data']); $sig = Base64UrlSafe::decode($update['signature']); $signatureVerified = AsymmetricCrypto::verify($data, $chan->getPublicKey(), $sig, true); if (!$signatureVerified) { // Invalid signature throw new ChannelSignatureFailed(); } // Now that we know it was signed by the channel, time to update $TreeUpdateArray[] = new TreeUpdate($chan, \json_decode($data, true)); } // Sort by ID \uasort($TreeUpdateArray, function (TreeUpdate $a, TreeUpdate $b) : int { return (int) ($a->getChannelId() <=> $b->getChannelId()); }); return $TreeUpdateArray; }
/** * Verify that this key update was signed by the master key for this supplier. * * @param array $supplierData * @param array $keyData * @param array $nodeData * @return bool */ protected function verifyMasterSignature(array $supplierData, array $keyData, array $nodeData) : bool { $masterData = \json_decode($nodeData['master'], true); if ($masterData === false) { return false; } foreach ($supplierData['signing_keys'] as $key) { if ($key['type'] !== 'master') { continue; } if (\hash_equals($keyData['public_key'], $masterData['public_key'])) { $publicKey = new SignaturePublicKey(\Sodium\hex2bin($masterData['public_key'])); $message = \json_encode($keyData); // If the signature is valid, we return true. return AsymmetricCrypto::verify($message, $publicKey, $masterData['signature']); } } // Fail closed. return false; }
/** * Verify the contents of a file * * @param $input (file handle) * @param SignaturePublicKey $publicKey * @param string $signature * @param mixed $encoding Which encoding scheme to use for the signature? * * @return bool */ protected static function verifyData(ReadOnlyFile $input, SignaturePublicKey $publicKey, string $signature, $encoding = Halite::ENCODE_BASE64URLSAFE) : bool { $checksum = self::checksumData($input, $publicKey, true); return AsymmetricCrypto::verify($checksum, $publicKey, $signature, $encoding); }