*/
namespace Friendica\Util;
-use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Core\Logger;
-use Friendica\Database\DBA;
use Friendica\Model\User;
use Friendica\Model\APContact;
-use Friendica\Protocol\ActivityPub;
-use Friendica\Util\DateTimeFormat;
/**
* @brief Implements HTTP Signatures per draft-cavage-http-signatures-07.
* @param $key
*
* @return array with verification data
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function verifyMagic($key)
{
* - \e string \b algorithm
* - \e array \b headers
* - \e string \b signature
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function parseSigheader($header)
{
$ret['signature'] = base64_decode(preg_replace('/\s+/', '', $matches[1]));
}
- if (($ret['signature']) && ($ret['algorithm']) && (!$ret['headers'])) {
+ if (!empty($ret['signature']) && !empty($ret['algorithm']) && empty($ret['headers'])) {
$ret['headers'] = ['date'];
}
* - \e string \b key
* - \e string \b alg
* - \e string \b data
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function decryptSigheader($header, $prvkey = null)
{
/**
* @brief Transmit given data to a target for a user
*
- * @param array $data Data that is about to be send
- * @param string $target The URL of the inbox
- * @param integer $uid User id of the sender
+ * @param array $data Data that is about to be send
+ * @param string $target The URL of the inbox
+ * @param integer $uid User id of the sender
*
* @return boolean Was the transmission successful?
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function transmit($data, $target, $uid)
{
/**
* @brief Fetches JSON data for a user
*
- * @param string $request request url
- * @param integer $uid User id of the requester
+ * @param string $request request url
+ * @param integer $uid User id of the requester
*
* @return array JSON array
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function fetch($request, $uid)
{
// Header data that is about to be signed.
$host = parse_url($request, PHP_URL_HOST);
$path = parse_url($request, PHP_URL_PATH);
+ $date = DateTimeFormat::utcNow(DateTimeFormat::HTTP);
- $headers = ['Host: ' . $host];
+ $headers = ['Date: ' . $date, 'Host: ' . $host];
- $signed_data = "(request-target): get " . $path . "\nhost: " . $host;
+ $signed_data = "(request-target): get " . $path . "\ndate: ". $date . "\nhost: " . $host;
$signature = base64_encode(Crypto::rsaSign($signed_data, $owner['uprvkey'], 'sha256'));
- $headers[] = 'Signature: keyId="' . $owner['url'] . '#main-key' . '",algorithm="rsa-sha256",headers="(request-target) host",signature="' . $signature . '"';
+ $headers[] = 'Signature: keyId="' . $owner['url'] . '#main-key' . '",algorithm="rsa-sha256",headers="(request-target) date host",signature="' . $signature . '"';
$headers[] = 'Accept: application/activity+json, application/ld+json';
* @param $content
* @param $http_headers
*
- * @return signer string
+ * @return string Signer
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function getSigner($content, $http_headers)
{
- $object = json_decode($content, true);
-
- if (empty($object)) {
+ if (empty($http_headers['HTTP_SIGNATURE'])) {
return false;
}
- $actor = JsonLD::fetchElement($object, 'actor', 'id');
+ if (!empty($content)) {
+ $object = json_decode($content, true);
+ if (empty($object)) {
+ return false;
+ }
+
+ $actor = JsonLD::fetchElement($object, 'actor', 'id');
+ } else {
+ $actor = '';
+ }
$headers = [];
$headers['(request-target)'] = strtolower($http_headers['REQUEST_METHOD']) . ' ' . $http_headers['REQUEST_URI'];
}
}
- /// @todo Check if the signed date field is in an acceptable range
+ // Check if the signed date field is in an acceptable range
+ if (in_array('date', $sig_block['headers'])) {
+ $diff = abs(strtotime($headers['date']) - time());
+ if ($diff > 300) {
+ Logger::log("Header date '" . $headers['date'] . "' is with " . $diff . " seconds out of the 300 second frame. The signature is invalid.");
+ return false;
+ }
+ }
// Check the content-length when it is part of the signed data
if (in_array('content-length', $sig_block['headers'])) {
* @param $actor
*
* @return array with actor url and public key
+ * @throws \Exception
*/
private static function fetchKey($id, $actor)
{