X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FOStatus%2Fclasses%2FMagicsig.php;h=42a11533b71ddead62093bac8bd9912f355b45bf;hb=e212f2ae77bd96f9ea8e90c7e51125ae74800efc;hp=c07a082495578790eea86f080323a3d5fbfffa5b;hpb=c0f65f6ea76ffa035cbf2c4126bedaae9d8752c8;p=quix0rs-gnu-social.git diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index c07a082495..42a11533b7 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -37,6 +37,9 @@ class Magicsig extends Managed_DataObject { const PUBLICKEYREL = 'magic-public-key'; + const DEFAULT_KEYLEN = 1024; + const DEFAULT_SIGALG = 'RSA-SHA256'; + public $__table = 'magicsig'; /** @@ -76,7 +79,7 @@ class Magicsig extends Managed_DataObject */ public $privateKey; - public function __construct($alg = 'RSA-SHA256') + public function __construct($alg=self::DEFAULT_SIGALG) { $this->alg = $alg; } @@ -92,16 +95,15 @@ class Magicsig extends Managed_DataObject { $obj = parent::getKV($k, $v); if ($obj instanceof Magicsig) { - // Please note we're replacing the $obj - // FIXME: There should be an import-key that modifies the fetched $obj - $obj = Magicsig::fromString($obj->keypair); + $obj->importKeys(); // Loads Crypt_RSA objects etc. - // Never allow less than 1024 bit keys. + // Throw out a big fat warning for keys of less than 1024 bits. ( // The only case these show up in would be imported or // legacy very-old-StatusNet generated keypairs. if (strlen($obj->publicKey->modulus->toBits()) < 1024) { - $obj->delete(); - return false; + common_log(LOG_WARNING, sprintf('Salmon key with <1024 bits (%d) belongs to profile with id==%d', + strlen($obj->publicKey->modulus->toBits()), + $obj->user_id)); } } @@ -118,7 +120,7 @@ class Magicsig extends Managed_DataObject ), 'primary key' => array('user_id'), 'foreign keys' => array( - 'magicsig_user_id_fkey' => array('user', array('user_id' => 'id')), + 'magicsig_user_id_fkey' => array('profile', array('user_id' => 'id')), ), ); } @@ -133,7 +135,7 @@ class Magicsig extends Managed_DataObject */ function insert() { - $this->keypair = $this->toString(); + $this->keypair = $this->toString(true); return parent::insert(); } @@ -144,61 +146,70 @@ class Magicsig extends Managed_DataObject * Warning: this can be very slow on systems without the GMP module. * Runtimes of 20-30 seconds are not unheard-of. * - * @param int $user_id id of local user we're creating a key for + * FIXME: More than 1024 bits please. But StatusNet _discards_ non-1024 bits, + * so we'll have to wait the last mohican out before switching defaults. + * + * @param User $user the local user (since we don't have remote private keys) */ - public function generate($user_id, $bits=1024) + public static function generate(User $user, $bits=self::DEFAULT_KEYLEN, $alg=self::DEFAULT_SIGALG) { + $magicsig = new Magicsig($alg); + $magicsig->user_id = $user->id; + $rsa = new Crypt_RSA(); $keypair = $rsa->createKey($bits); - $rsa->loadKey($keypair['privatekey']); + $magicsig->privateKey = new Crypt_RSA(); + $magicsig->privateKey->loadKey($keypair['privatekey']); - $this->privateKey = new Crypt_RSA(); - $this->privateKey->loadKey($keypair['privatekey']); + $magicsig->publicKey = new Crypt_RSA(); + $magicsig->publicKey->loadKey($keypair['publickey']); - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($keypair['publickey']); + $magicsig->insert(); // will do $this->keypair = $this->toString(true); + $magicsig->importKeys(); // seems it's necessary to re-read keys from text keypair - $this->user_id = $user_id; - $this->insert(); + return $magicsig; } /** * Encode the keypair or public key as a string. * - * @param boolean $full_pair set to false to leave out the private key. + * @param boolean $full_pair set to true to include the private key. * @return string */ - public function toString($full_pair = true) + public function toString($full_pair=false) { $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()); } return 'RSA.' . $mod . '.' . $exp . $private_exp; } + public function exportPublicKey($format=CRYPT_RSA_PUBLIC_FORMAT_PKCS1) + { + $this->publicKey->setPublicKey(); + return $this->publicKey->getPublicKey($format); + } + /** - * Decode a string representation of an RSA public key or keypair - * as a Magicsig object which can be used to sign or verify. + * importKeys will load the object's keypair string, which initiates + * loadKey() and configures Crypt_RSA objects. * - * @param string $text - * @return Magicsig + * @param string $keypair optional, otherwise the object's "keypair" property will be used */ - public static function fromString($text) + public function importKeys($keypair=null) { - $magic_sig = new Magicsig(); - - // remove whitespace - $text = preg_replace('/\s+/', '', $text); + $this->keypair = $keypair===null ? $this->keypair : preg_replace('/\s+/', '', $keypair); // parse components - if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) { - return false; + if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(\.([^\.]+))?/', $this->keypair, $matches)) { + common_debug('Magicsig error: RSA key not found in provided string.'); + throw new ServerException('RSA key not found in keypair string.'); } $mod = $matches[1]; @@ -209,12 +220,10 @@ class Magicsig extends Managed_DataObject $private_exp = false; } - $magic_sig->loadKey($mod, $exp, 'public'); + $this->loadKey($mod, $exp, 'public'); if ($private_exp) { - $magic_sig->loadKey($mod, $private_exp, 'private'); + $this->loadKey($mod, $private_exp, 'private'); } - - return $magic_sig; } /** @@ -227,11 +236,9 @@ class Magicsig extends Managed_DataObject */ public function loadKey($mod, $exp, $type = 'public') { - common_log(LOG_DEBUG, "Adding ".$type." key: (".$mod .', '. $exp .")"); - $rsa = new Crypt_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash('sha256'); + $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); + $rsa->setHash($this->getHash()); $rsa->modulus = new Math_BigInteger(Magicsig::base64_url_decode($mod), 256); $rsa->k = strlen($rsa->modulus->toBytes()); $rsa->exponent = new Math_BigInteger(Magicsig::base64_url_decode($exp), 256); @@ -257,15 +264,14 @@ class Magicsig extends Managed_DataObject * Returns the name of a hash function to use for signing with this key. * * @return string - * @fixme is this used? doesn't seem to be called by name. */ public function getHash() { switch ($this->alg) { - case 'RSA-SHA256': return 'sha256'; } + throw new ServerException('Unknown or unsupported hash algorithm for Salmon'); } /** @@ -273,23 +279,26 @@ class Magicsig extends Managed_DataObject * using our private key. * * @param string $bytes as raw byte string - * @return string base64-encoded signature + * @return string base64url-encoded signature */ public function sign($bytes) { $sig = $this->privateKey->sign($bytes); + if ($sig === false) { + throw new ServerException('Could not sign data'); + } return Magicsig::base64_url_encode($sig); } /** * * @param string $signed_bytes as raw byte string - * @param string $signature as base64 + * @param string $signature as base64url encoded * @return boolean */ public function verify($signed_bytes, $signature) { - $signature = Magicsig::base64_url_decode($signature); + $signature = self::base64_url_decode($signature); return $this->publicKey->verify($signed_bytes, $signature); }