From c470f7f6d15e0eed2ab713376cf7172ffcb5a7ee Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 11 Dec 2018 12:48:27 -0100 Subject: [PATCH] Signing Object, adding Signature and @context entry --- lib/Model/ActivityPub/ACore.php | 45 ++++++++++++++++++++++++++----- lib/Model/LinkedDataSignature.php | 27 ++++++++++++++++++- lib/Service/ActivityService.php | 21 +++++++++++++++ 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index 3e76e2fc..1790718b 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -37,6 +37,7 @@ use OCA\Social\Exceptions\ActivityCantBeVerifiedException; use OCA\Social\Exceptions\InvalidOriginException; use OCA\Social\Exceptions\InvalidResourceEntryException; use OCA\Social\Exceptions\UrlCloudException; +use OCA\Social\Model\LinkedDataSignature; use OCA\Social\Service\ActivityPub\ICoreService; @@ -74,6 +75,10 @@ abstract class ACore extends Item implements JsonSerializable { /** @var ICoreService */ private $saveAs; + /** @var LinkedDataSignature */ + private $signature = null; + + /** * Core constructor. * @@ -167,6 +172,32 @@ abstract class ACore extends Item implements JsonSerializable { } + /** + * @return bool + */ + public function gotSignature(): bool { + return ($this->signature !== null); + } + + /** + * @return LinkedDataSignature + */ + public function getSignature(): LinkedDataSignature { + return $this->signature; + } + + /** + * @param LinkedDataSignature $signature + * + * @return ACore + */ + public function setSignature(LinkedDataSignature $signature): Acore { + $this->signature = $signature; + + return $this; + } + + /** * @param ICoreService $class */ @@ -507,13 +538,14 @@ abstract class ACore extends Item implements JsonSerializable { * @return array */ public function jsonSerialize(): array { + $context = [self::CONTEXT_ACTIVITYSTREAMS]; + if ($this->gotSignature()) { + $this->entries['signature'] = $this->getSignature(); + array_push($context, self::CONTEXT_SECURITY); + } + if ($this->isRoot()) { - $this->addEntryArray( - '@context', [ - self::CONTEXT_ACTIVITYSTREAMS, - self::CONTEXT_SECURITY - ] - ); + $this->addEntryArray('@context', $context); } $this->addEntry('id', $this->getId()); @@ -540,7 +572,6 @@ abstract class ACore extends Item implements JsonSerializable { $this->addEntry('published', $this->getPublished()); $this->addEntryArray('tag', $this->getTags()); -// $arr = $this->getEntries(); if ($this->gotObject()) { $this->addEntryItem('object', $this->getObject()); } else { diff --git a/lib/Model/LinkedDataSignature.php b/lib/Model/LinkedDataSignature.php index 71e2a6c2..689a5091 100644 --- a/lib/Model/LinkedDataSignature.php +++ b/lib/Model/LinkedDataSignature.php @@ -205,7 +205,28 @@ class LinkedDataSignature implements JsonSerializable { } + /** + * @throws LinkedDataSignatureMissingException + */ public function sign() { + $header = [ + '@context' => 'https://w3id.org/identity/v1', + 'creator' => $this->getCreator(), + 'created' => $this->getCreated() + ]; + + $hash = $this->hashedCanonicalize($header) . $this->hashedCanonicalize($this->getObject()); + + $algo = OPENSSL_ALGO_SHA256; + if ($this->getType() === 'RsaSignature2017') { + $algo = OPENSSL_ALGO_SHA256; + } + + if (!openssl_sign($hash, $signed, $this->getPrivateKey(), $algo)) { + throw new LinkedDataSignatureMissingException(); + } + + $this->setSignatureValue(base64_encode($signed)); } @@ -235,7 +256,11 @@ class LinkedDataSignature implements JsonSerializable { return false; } - + /** + * @param array $data + * + * @return string + */ private function hashedCanonicalize(array $data): string { $object = json_decode(json_encode($data), false); $res = jsonld_normalize( diff --git a/lib/Service/ActivityService.php b/lib/Service/ActivityService.php index 3d88f2f1..37b3481a 100644 --- a/lib/Service/ActivityService.php +++ b/lib/Service/ActivityService.php @@ -161,6 +161,7 @@ class ActivityService { $activity = new Create(); // $this->activityStreamsService->initCore($activity); + $this->signObject($actor, $item); $activity->setObject($item); $activity->setId($item->getId() . '/activity'); @@ -451,6 +452,26 @@ class ActivityService { } + /** + * @param Person $actor + * @param ACore $object + */ + public function signObject(Person $actor, ACore &$object) { + $signature = new LinkedDataSignature(); + $signature->setPrivateKey($actor->getPrivateKey()); + $signature->setType('RsaSignature2017'); + $signature->setCreator($actor->getId() . '#main-key'); + $signature->setCreated($object->getPublished()); + $signature->setObject(json_decode(json_encode($object), true)); + + try { + $signature->sign(); + $object->setSignature($signature); + } catch (LinkedDataSignatureMissingException $e) { + } + } + + /** * @param ACore $object *