From 255b6a14a8d993a086dc790e8c4dbe64ce6e3e48 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 8 Nov 2020 12:55:32 +0000 Subject: less hubloc confusion --- Zotlabs/Lib/JSalmon.php | 2 +- Zotlabs/Lib/Zotfinger.php | 7 +++-- Zotlabs/Module/Channel.php | 2 +- Zotlabs/Module/Connedit.php | 15 ++-------- Zotlabs/Module/Zot_probe.php | 2 +- Zotlabs/Web/HTTPSig.php | 66 ++++++++++++++++++++++++++++++-------------- Zotlabs/Zot6/Receiver.php | 2 +- 7 files changed, 56 insertions(+), 40 deletions(-) diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php index 67512046f..48a4e649b 100644 --- a/Zotlabs/Lib/JSalmon.php +++ b/Zotlabs/Lib/JSalmon.php @@ -51,7 +51,7 @@ class JSalmon { . base64url_encode($x['encoding'],true) . '.' . base64url_encode($x['alg'],true); - $key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id'])); + $key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id'])); logger('key: ' . print_r($key,true)); if($key['portable_id'] && $key['public_key']) { if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) { diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php index 722e34dfc..e853d6ebc 100644 --- a/Zotlabs/Lib/Zotfinger.php +++ b/Zotlabs/Lib/Zotfinger.php @@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig; class Zotfinger { - static function exec($resource,$channel = null) { + static function exec($resource,$channel = null, $verify = true) { if(! $resource) { return false; @@ -41,8 +41,9 @@ class Zotfinger { logger('fetch: ' . print_r($x,true)); if($x['success']) { - - $result['signature'] = HTTPSig::verify($x); + if ($verify) { + $result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6'); + } $result['data'] = json_decode($x['body'],true); diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 307be048a..dc8e9e1c5 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -60,7 +60,7 @@ class Channel extends Controller { if(Libzot::is_zot_request()) { - $sigdata = HTTPSig::verify(file_get_contents('php://input')); + $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ])); diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 0fc807d42..becf8460d 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -294,8 +294,8 @@ class Connedit extends Controller { intval($channel['channel_id']) ); if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) { - $xarr = array(); - $xarr['verb'] = ACTIVITY_FRIEND; + $xarr = []; + $xarr['item_wall'] = 1; $xarr['item_origin'] = 1; $xarr['item_thread_top'] = 1; @@ -305,17 +305,6 @@ class Connedit extends Controller { $xarr['deny_cid'] = $channel['channel_deny_cid']; $xarr['deny_gid'] = $channel['channel_deny_gid']; $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); - $obj = array( - 'type' => ACTIVITY_OBJ_PERSON, - 'title' => App::$poi['xchan_name'], - 'id' => App::$poi['xchan_hash'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => App::$poi['xchan_url']), - array('rel' => 'photo', 'type' => App::$poi['xchan_photo_mimetype'], 'href' => App::$poi['xchan_photo_l']) - ), - ); - $xarr['obj'] = json_encode($obj); - $xarr['obj_type'] = ACTIVITY_OBJ_PERSON; $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; diff --git a/Zotlabs/Module/Zot_probe.php b/Zotlabs/Module/Zot_probe.php index 648ed2175..7585affdf 100644 --- a/Zotlabs/Module/Zot_probe.php +++ b/Zotlabs/Module/Zot_probe.php @@ -34,7 +34,7 @@ class Zot_probe extends \Zotlabs\Web\Controller { $o .= '
' . htmlspecialchars($x['header']) . '
' . EOL; - $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x),true)) . EOL; + $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x, EMPTY_STR, 'zot6'),true)) . EOL; $o .= '
' . htmlspecialchars(json_encode(json_decode($x['body']),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '
' . EOL; diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index 827e0d779..42426afb1 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -76,7 +76,7 @@ class HTTPSig { // See draft-cavage-http-signatures-10 - static function verify($data,$key = '') { + static function verify($data,$key = '', $keytype = '') { $body = $data; $headers = null; @@ -151,7 +151,7 @@ class HTTPSig { $result['signer'] = $sig_block['keyId']; - $key = self::get_key($key,$result['signer']); + $key = self::get_key($key,$keytype,$result['signer']); if(! ($key && $key['public_key'])) { return $result; @@ -162,13 +162,26 @@ class HTTPSig { logger('verified: ' . $x, LOGGER_DEBUG); if(! $x) { - logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key')); - $sig_block['signature'] = base64_encode($sig_block['signature']); - logger('affected sigblock: ' . print_r($sig_block,true)); - logger('signed_data: ' . print_r($signed_data,true)); - logger('headers: ' . print_r($headers,true)); - logger('server: ' . print_r($_SERVER,true)); - return $result; + + // try again, ignoring the local actor (xchan) cache and refetching the key + // from its source + + $fkey = self::get_key($key,$keytype,$result['signer'],true); + + if ($fkey && $fkey['public_key']) { + $y = rsa_verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm); + logger('verified: (cache reload) ' . $x, LOGGER_DEBUG); + } + + if (! $y) { + logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key')); + $sig_block['signature'] = base64_encode($sig_block['signature']); + logger('affected sigblock: ' . print_r($sig_block,true)); + logger('headers: ' . print_r($headers,true)); + logger('server: ' . print_r($_SERVER,true)); + return $result; + } + } $result['portable_id'] = $key['portable_id']; @@ -187,12 +200,17 @@ class HTTPSig { } logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false')); + if (! $result['content_valid']) { + logger('invalid content signature: data ' . print_r($data,true)); + logger('invalid content signature: headers ' . print_r($headers,true)); + logger('invalid content signature: body ' . print_r($body,true)); + } } return $result; } - static function get_key($key,$id) { + static function get_key($key,$keytype,$id) { if($key) { if(function_exists($key)) { @@ -201,6 +219,13 @@ class HTTPSig { return [ 'public_key' => $key ]; } + if($keytype === 'zot6') { + $key = self::get_zotfinger_key($id,$force); + if($key) { + return $key; + } + } + if(strpos($id,'#') === false) { $key = self::get_webfinger_key($id); } @@ -243,7 +268,7 @@ class HTTPSig { $url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id); - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network in ('zot6', 'activitypub')", dbesc(str_replace('acct:','',$url)), dbesc($url) ); @@ -303,18 +328,15 @@ class HTTPSig { return (($key['public_key']) ? $key : false); } - function get_zotfinger_key($id) { - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network = 'zot6'", dbesc(str_replace('acct:','',$id)), dbesc($id) ); - $x = Libzot::zot_record_preferred($x); - - if($x && $x['xchan_pubkey']) { - return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ]; + if($x && $x[0]['xchan_pubkey']) { + return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ]; } $wf = Webfinger::exec($id); @@ -330,13 +352,18 @@ class HTTPSig { continue; } if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) { - $z = \Zotlabs\Lib\Zotfinger::exec($l['href']); + + // The third argument to Zotfinger::exec() tells it not to verify signatures + // Since we're inside a function that is fetching keys with which to verify signatures, + // this is necessary to prevent infinite loops. + + $z = \Zotlabs\Lib\Zotfinger::exec($l['href'],null,false); if($z) { $i = Libzot::import_xchan($z['data']); if($i['success']) { $key['portable_id'] = $i['hash']; - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' and hubloc_network = 'zot6'", dbesc($l['href']) ); if($x) { @@ -485,7 +512,6 @@ class HTTPSig { if(preg_match('/iv="(.*?)"/ism',$header,$matches)) $header = self::decrypt_sigheader($header); - if(preg_match('/keyId="(.*?)"/ism',$header,$matches)) $ret['keyId'] = $matches[1]; if(preg_match('/algorithm="(.*?)"/ism',$header,$matches)) diff --git a/Zotlabs/Zot6/Receiver.php b/Zotlabs/Zot6/Receiver.php index 9e70ab318..a9a7ab0df 100644 --- a/Zotlabs/Zot6/Receiver.php +++ b/Zotlabs/Zot6/Receiver.php @@ -155,7 +155,7 @@ class Receiver { $result = false; - $this->sigdata = HTTPSig::verify($this->rawdata); + $this->sigdata = HTTPSig::verify($this->rawdata, EMPTY_STR, 'zot6'); if ($this->sigdata && $this->sigdata['header_signed'] && $this->sigdata['header_valid']) { $result = true; -- cgit v1.2.3