From 0bc122ff58d039dfbd7b9005eb4267df0d67a883 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 2 Jun 2014 21:50:40 +0200 Subject: [PATCH] Magicsig::generate is now static This also fixes a problem with "initial salmon slap", which was a problem for newly registered accounts which would have their first salmon slap fail to distribute since there was a problem with Magicsig keys. Apparently we have to re-read them with importKeys so the Crypt_RSA objects publicKey and privateKey match later instances of them. I think it may have been that generate() doesn't specify a signatureMode, but I leave experimentation of that to the future. --- plugins/OStatus/OStatusPlugin.php | 4 +-- plugins/OStatus/classes/Magicsig.php | 23 ++++++++------ plugins/OStatus/lib/magicenvelope.php | 45 +++++++++++++++------------ 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index b80f965d81..704b457272 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -1344,9 +1344,7 @@ class OStatusPlugin extends Plugin // Get this profile's keypair $magicsig = Magicsig::getKV('user_id', $target->id); if (!$magicsig instanceof Magicsig && $target->isLocal()) { - // No keypair yet, let's generate one. Only for local users. - $magicsig = new Magicsig(); - $magicsig->generate($target->getUser()); + $magicsig = Magicsig::generate($target->getUser()); } if ($magicsig instanceof Magicsig) { diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 7c249920a9..82ee710559 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -132,7 +132,7 @@ class Magicsig extends Managed_DataObject */ function insert() { - $this->keypair = $this->toString(); + $this->keypair = $this->toString(true); return parent::insert(); } @@ -145,20 +145,25 @@ class Magicsig extends Managed_DataObject * * @param User $user the local user (since we don't have remote private keys) */ - public function generate(User $user, $bits=1024) + public static function generate(User $user, $bits=1024, $alg='RSA-SHA256') { + $magicsig = new Magicsig($alg); + $magicsig->user_id = $user->id; + $rsa = new Crypt_RSA(); $keypair = $rsa->createKey($bits); - $this->privateKey = new Crypt_RSA(); - $this->privateKey->loadKey($keypair['privatekey']); + $magicsig->privateKey = new Crypt_RSA(); + $magicsig->privateKey->loadKey($keypair['privatekey']); - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($keypair['publickey']); + $magicsig->publicKey = new Crypt_RSA(); + $magicsig->publicKey->loadKey($keypair['publickey']); - $this->user_id = $user->id; - $this->insert(); + $magicsig->insert(); // will do $this->keypair = $this->toString(true); + $magicsig->importKeys(); // seems it's necessary to re-read keys from text keypair + + return $magicsig; } /** @@ -172,7 +177,7 @@ class Magicsig extends Managed_DataObject $mod = Magicsig::base64_url_encode($this->publicKey->modulus->toBytes()); $exp = Magicsig::base64_url_encode($this->publicKey->exponent->toBytes()); $private_exp = ''; - if ($full_pair && $this->privateKey->exponent->toBytes()) { + if ($full_pair && $this->privateKey instanceof Crypt_RSA && $this->privateKey->exponent->toBytes()) { $private_exp = '.' . Magicsig::base64_url_encode($this->privateKey->exponent->toBytes()); } diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 84ba2ba296..1d18d6934a 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -153,21 +153,23 @@ class MagicEnvelope * @param $text * @param $mimetype * @param Magicsig $magicsig Magicsig with private key available. + * * @return MagicEnvelope object with all properties set + * + * @throws Exception of various kinds on signing failure */ - public static function signMessage($text, $mimetype, Magicsig $magicsig) + public function signMessage($text, $mimetype, Magicsig $magicsig) { - $magic_env = new MagicEnvelope(); + assert($magicsig->privateKey instanceof Crypt_RSA); // Prepare text and metadata for signing - $magic_env->data = Magicsig::base64_url_encode($text); - $magic_env->data_type = $mimetype; - $magic_env->encoding = self::ENCODING; - $magic_env->alg = $magicsig->getName(); - // Get the actual signature - $magic_env->sig = $magicsig->sign($magic_env->signingText()); + $this->data = Magicsig::base64_url_encode($text); + $this->data_type = $mimetype; + $this->encoding = self::ENCODING; + $this->alg = $magicsig->getName(); - return $magic_env; + // Get the actual signature + $this->sig = $magicsig->sign($this->signingText()); } /** @@ -182,7 +184,7 @@ class MagicEnvelope $xs->element('me:data', array('type' => $this->data_type), $this->data); $xs->element('me:encoding', null, $this->encoding); $xs->element('me:alg', null, $this->alg); - $xs->element('me:sig', null, $this->sig); + $xs->element('me:sig', null, $this->getSignature()); $xs->elementEnd('me:env'); $string = $xs->getString(); @@ -220,7 +222,7 @@ class MagicEnvelope $prov->appendChild($enc); $alg = $dom->createElementNS(self::NS, 'me:alg', $this->alg); $prov->appendChild($alg); - $sig = $dom->createElementNS(self::NS, 'me:sig', $this->sig); + $sig = $dom->createElementNS(self::NS, 'me:sig', $this->getSignature()); $prov->appendChild($sig); $dom->documentElement->appendChild($prov); @@ -231,6 +233,11 @@ class MagicEnvelope return $dom; } + public function getSignature() + { + return $this->sig; + } + /** * Find the author URI referenced in the payload Atom entry. * @@ -280,7 +287,7 @@ class MagicEnvelope return false; } - return $magicsig->verify($this->signingText(), $this->sig); + return $magicsig->verify($this->signingText(), $this->getSignature()); } /** @@ -326,24 +333,22 @@ class MagicEnvelope * @param string $text XML fragment to sign, assumed to be Atom * @param User $user User who cryptographically signs $text * - * @return string XML string representation of magic envelope + * @return MagicEnvelope object complete with signature * * @throws Exception on bad profile input or key generation problems - * @fixme if signing fails, this seems to return the original text without warning. Is there a reason for this? */ public static function signAsUser($text, User $user) { // Find already stored key $magicsig = Magicsig::getKV('user_id', $user->id); if (!$magicsig instanceof Magicsig) { - // No keypair yet, let's generate one. - $magicsig = new Magicsig(); - $magicsig->generate($user); + $magicsig = Magicsig::generate($user); } + assert($magicsig instanceof Magicsig); + assert($magicsig->privateKey instanceof Crypt_RSA); - $magic_env = self::signMessage($text, 'application/atom+xml', $magicsig); - - assert($magic_env instanceof MagicEnvelope); + $magic_env = new MagicEnvelope(); + $magic_env->signMessage($text, 'application/atom+xml', $magicsig); return $magic_env; }