3 namespace Friendica\Util;
5 use Friendica\Core\Logger;
6 use Friendica\Model\APContact;
9 * @brief Implements JSON-LD signatures
11 * Ported from Osada: https://framagit.org/macgirvin/osada
15 public static function isSigned($data)
17 return !empty($data['signature']);
20 public static function getSigner($data)
22 if (!self::isSigned($data)) {
26 $actor = JsonLD::fetchElement($data, 'actor', 'id');
27 if (empty($actor) || !is_string($actor)) {
31 $profile = APContact::getByURL($actor);
32 if (empty($profile['pubkey'])) {
35 $pubkey = $profile['pubkey'];
37 $ohash = self::hash(self::signableOptions($data['signature']));
38 $dhash = self::hash(self::signableData($data));
40 $x = Crypto::rsaVerify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey);
41 Logger::log('LD-verify: ' . intval($x));
50 public static function sign($data, $owner)
53 'type' => 'RsaSignature2017',
54 'nonce' => Strings::getRandomHex(64),
55 'creator' => $owner['url'] . '#main-key',
56 'created' => DateTimeFormat::utcNow(DateTimeFormat::ATOM)
59 $ohash = self::hash(self::signableOptions($options));
60 $dhash = self::hash(self::signableData($data));
61 $options['signatureValue'] = base64_encode(Crypto::rsaSign($ohash . $dhash, $owner['uprvkey']));
63 return array_merge($data, ['signature' => $options]);
66 private static function signableData($data)
68 unset($data['signature']);
72 private static function signableOptions($options)
74 $newopts = ['@context' => 'https://w3id.org/identity/v1'];
76 unset($options['type']);
77 unset($options['id']);
78 unset($options['signatureValue']);
80 return array_merge($newopts, $options);
83 private static function hash($obj)
85 return hash('sha256', JsonLD::normalize($obj));