3 namespace Friendica\Util;
5 use Friendica\Core\Logger;
6 use Friendica\Util\JsonLD;
7 use Friendica\Util\DateTimeFormat;
8 use Friendica\Protocol\ActivityPub;
9 use Friendica\Model\APContact;
12 * @brief Implements JSON-LD signatures
14 * Ported from Osada: https://framagit.org/macgirvin/osada
18 public static function isSigned($data)
20 return !empty($data['signature']);
23 public static function getSigner($data)
25 if (!self::isSigned($data)) {
29 $actor = JsonLD::fetchElement($data, 'actor', 'id');
30 if (empty($actor) || !is_string($actor)) {
34 $profile = APContact::getByURL($actor);
35 if (empty($profile['pubkey'])) {
38 $pubkey = $profile['pubkey'];
40 $ohash = self::hash(self::signableOptions($data['signature']));
41 $dhash = self::hash(self::signableData($data));
43 $x = Crypto::rsaVerify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey);
44 Logger::log('LD-verify: ' . intval($x));
53 public static function sign($data, $owner)
56 'type' => 'RsaSignature2017',
57 'nonce' => Strings::getRandomHex(64),
58 'creator' => $owner['url'] . '#main-key',
59 'created' => DateTimeFormat::utcNow(DateTimeFormat::ATOM)
62 $ohash = self::hash(self::signableOptions($options));
63 $dhash = self::hash(self::signableData($data));
64 $options['signatureValue'] = base64_encode(Crypto::rsaSign($ohash . $dhash, $owner['uprvkey']));
66 return array_merge($data, ['signature' => $options]);
69 private static function signableData($data)
71 unset($data['signature']);
75 private static function signableOptions($options)
77 $newopts = ['@context' => 'https://w3id.org/identity/v1'];
79 unset($options['type']);
80 unset($options['id']);
81 unset($options['signatureValue']);
83 return array_merge($newopts, $options);
86 private static function hash($obj)
88 return hash('sha256', JsonLD::normalize($obj));