X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FOStatus%2Fclasses%2FMagicsig.php;h=c07a082495578790eea86f080323a3d5fbfffa5b;hb=c00491cd7a29a9ef16d6e6bfa54505d4c9a522fe;hp=20025c37a6a8c0e3a8aa7ba9afa80d4c778b8e3d;hpb=59119482ca34540bd7f0a2a1aa994de1d5328ea2;p=quix0rs-gnu-social.git diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 20025c37a6..c07a082495 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -27,19 +27,53 @@ * @link http://status.net/ */ +if (!defined('STATUSNET')) { + exit(1); +} + require_once 'Crypt/RSA.php'; -class Magicsig extends Memcached_DataObject +class Magicsig extends Managed_DataObject { const PUBLICKEYREL = 'magic-public-key'; public $__table = 'magicsig'; + /** + * Key to user.id/profile.id for the local user whose key we're storing. + * + * @var int + */ public $user_id; + + /** + * Flattened string representation of the key pair; callers should + * usually use $this->publicKey and $this->privateKey directly, + * which hold live Crypt_RSA key objects. + * + * @var string + */ public $keypair; + + /** + * Crypto algorithm used for this key; currently only RSA-SHA256 is supported. + * + * @var string + */ public $alg; + /** + * Public RSA key; gets serialized in/out via $this->keypair string. + * + * @var Crypt_RSA + */ public $publicKey; + + /** + * PrivateRSA key; gets serialized in/out via $this->keypair string. + * + * @var Crypt_RSA + */ public $privateKey; public function __construct($alg = 'RSA-SHA256') @@ -47,16 +81,25 @@ class Magicsig extends Memcached_DataObject $this->alg = $alg; } - public /*static*/ function staticGet($k, $v=null) + /** + * Fetch a Magicsig object from the cache or database on a field match. + * + * @param string $k + * @param mixed $v + * @return Magicsig + */ + static function getKV($k, $v=null) { - $obj = parent::staticGet(__CLASS__, $k, $v); - if (!empty($obj)) { + $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); - // Double check keys: Crypt_RSA did not - // consistently generate good keypairs. - // We've also moved to 1024 bit keys. - if (strlen($obj->publicKey->modulus->toBits()) != 1024) { + // Never allow less than 1024 bit keys. + // 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; } @@ -65,40 +108,29 @@ class Magicsig extends Memcached_DataObject return $obj; } - - function table() + public static function schemaDef() { return array( - 'user_id' => DB_DATAOBJECT_INT, - 'keypair' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, - 'alg' => DB_DATAOBJECT_STR + 'fields' => array( + 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'), + 'keypair' => array('type' => 'text', 'description' => 'keypair text representation'), + 'alg' => array('type' => 'varchar', 'length' => 64, 'description' => 'algorithm'), + ), + 'primary key' => array('user_id'), + 'foreign keys' => array( + 'magicsig_user_id_fkey' => array('user', array('user_id' => 'id')), + ), ); } - static function schemaDef() - { - return array(new ColumnDef('user_id', 'integer', - null, false, 'PRI'), - new ColumnDef('keypair', 'text', - false, false), - new ColumnDef('alg', 'varchar', - 64, false)); - } - - function keys() - { - return array_keys($this->keyTypes()); - } - - function keyTypes() - { - return array('user_id' => 'K'); - } - - function sequenceKey() { - return array(false, false, false); - } - + /** + * Save this keypair into the database. + * + * Overloads default insert behavior to encode the live key objects + * as a flat string for storage. + * + * @return mixed + */ function insert() { $this->keypair = $this->toString(); @@ -106,11 +138,19 @@ class Magicsig extends Memcached_DataObject return parent::insert(); } - public function generate($user_id) + /** + * Generate a new keypair for a local user and store in the database. + * + * 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 + */ + public function generate($user_id, $bits=1024) { $rsa = new Crypt_RSA(); - $keypair = $rsa->createKey(); + $keypair = $rsa->createKey($bits); $rsa->loadKey($keypair['privatekey']); @@ -124,6 +164,12 @@ class Magicsig extends Memcached_DataObject $this->insert(); } + /** + * Encode the keypair or public key as a string. + * + * @param boolean $full_pair set to false to leave out the private key. + * @return string + */ public function toString($full_pair = true) { $mod = Magicsig::base64_url_encode($this->publicKey->modulus->toBytes()); @@ -136,6 +182,13 @@ class Magicsig extends Memcached_DataObject return 'RSA.' . $mod . '.' . $exp . $private_exp; } + /** + * Decode a string representation of an RSA public key or keypair + * as a Magicsig object which can be used to sign or verify. + * + * @param string $text + * @return Magicsig + */ public static function fromString($text) { $magic_sig = new Magicsig(); @@ -164,6 +217,14 @@ class Magicsig extends Memcached_DataObject return $magic_sig; } + /** + * Fill out $this->privateKey or $this->publicKey with a Crypt_RSA object + * representing the give key (as mod/exponent pair). + * + * @param string $mod base64-encoded + * @param string $exp base64-encoded exponent + * @param string $type one of 'public' or 'private' + */ public function loadKey($mod, $exp, $type = 'public') { common_log(LOG_DEBUG, "Adding ".$type." key: (".$mod .', '. $exp .")"); @@ -182,11 +243,22 @@ class Magicsig extends Memcached_DataObject } } + /** + * Returns the name of the crypto algorithm used for this key. + * + * @return string + */ public function getName() { return $this->alg; } + /** + * 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) { @@ -196,24 +268,48 @@ class Magicsig extends Memcached_DataObject } } + /** + * Generate base64-encoded signature for the given byte string + * using our private key. + * + * @param string $bytes as raw byte string + * @return string base64-encoded signature + */ public function sign($bytes) { $sig = $this->privateKey->sign($bytes); return Magicsig::base64_url_encode($sig); } + /** + * + * @param string $signed_bytes as raw byte string + * @param string $signature as base64 + * @return boolean + */ public function verify($signed_bytes, $signature) { $signature = Magicsig::base64_url_decode($signature); return $this->publicKey->verify($signed_bytes, $signature); } - + /** + * URL-encoding-friendly base64 variant encoding. + * + * @param string $input + * @return string + */ public static function base64_url_encode($input) { return strtr(base64_encode($input), '+/', '-_'); } + /** + * URL-encoding-friendly base64 variant decoding. + * + * @param string $input + * @return string + */ public static function base64_url_decode($input) { return base64_decode(strtr($input, '-_', '+/'));