From 1bfe1283aa38454369f29883411a6c012c88df59 Mon Sep 17 00:00:00 2001 From: Friendika Date: Tue, 9 Aug 2011 18:55:46 -0700 Subject: crypto stuff --- boot.php | 2 +- images/friendika-16.png | Bin 770 -> 756 bytes include/certfns.php | 130 ---------------------------------- include/crypto.php | 184 ++++++++++++++++++++++++++++++++++++++++++++++++ include/diaspora.php | 25 ++----- include/network.php | 14 ++++ include/salmon.php | 31 ++------ include/text.php | 6 +- mod/receive.php | 2 +- mod/salmon.php | 44 ++++-------- mod/xrd.php | 14 ++-- 11 files changed, 232 insertions(+), 220 deletions(-) delete mode 100644 include/certfns.php create mode 100644 include/crypto.php diff --git a/boot.php b/boot.php index b5768c796..3b8c27f60 100644 --- a/boot.php +++ b/boot.php @@ -7,7 +7,7 @@ require_once('include/text.php'); require_once("include/pgettext.php"); -define ( 'FRIENDIKA_VERSION', '2.2.1066' ); +define ( 'FRIENDIKA_VERSION', '2.2.1067' ); define ( 'DFRN_PROTOCOL_VERSION', '2.21' ); define ( 'DB_UPDATE_VERSION', 1079 ); diff --git a/images/friendika-16.png b/images/friendika-16.png index 3793508fb..745b7ac6c 100644 Binary files a/images/friendika-16.png and b/images/friendika-16.png differ diff --git a/include/certfns.php b/include/certfns.php deleted file mode 100644 index aa84cfeb6..000000000 --- a/include/certfns.php +++ /dev/null @@ -1,130 +0,0 @@ -SetIntBuffer($Modulus); - $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); - $publicExponent->SetIntBuffer($PublicExponent); - $keySequenceItems = array($modulus, $publicExponent); - $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); - $keySequence->SetSequence($keySequenceItems); - //Encode bit string - $bitStringValue = $keySequence->Encode(); - $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte - $bitString = new ASNValue(ASNValue::TAG_BITSTRING); - $bitString->Value = $bitStringValue; - //Encode body - $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode(); - $body = new ASNValue(ASNValue::TAG_SEQUENCE); - $body->Value = $bodyValue; - //Get DER encoded public key: - $PublicDER = $body->Encode(); - return $PublicDER; -} - - -function pkcs1_encode($Modulus,$PublicExponent) { - //Encode key sequence - $modulus = new ASNValue(ASNValue::TAG_INTEGER); - $modulus->SetIntBuffer($Modulus); - $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); - $publicExponent->SetIntBuffer($PublicExponent); - $keySequenceItems = array($modulus, $publicExponent); - $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); - $keySequence->SetSequence($keySequenceItems); - //Encode bit string - $bitStringValue = $keySequence->Encode(); - return $bitStringValue; -} - - -function metopem($m,$e) { - $der = pkcs8_encode($m,$e); - $key = DerToPem($der,false); - return $key; -} - - -function pubrsatome($key,&$m,&$e) { - require_once('library/asn1.php'); - require_once('include/salmon.php'); - - $lines = explode("\n",$key); - unset($lines[0]); - unset($lines[count($lines)]); - $x = base64_decode(implode('',$lines)); - - $r = ASN_BASE::parseASNString($x); - - $m = base64url_decode($r[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData); -} - - -function rsatopem($key) { - pubrsatome($key,$m,$e); - return(metopem($m,$e)); -} - -function pemtorsa($key) { - pemtome($key,$m,$e); - return(metorsa($m,$e)); -} - -function pemtome($key,&$m,&$e) { - require_once('include/salmon.php'); - $lines = explode("\n",$key); - unset($lines[0]); - unset($lines[count($lines)]); - $x = base64_decode(implode('',$lines)); - - $r = ASN_BASE::parseASNString($x); - - $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); -} - -function metorsa($m,$e) { - $der = pkcs1_encode($m,$e); - $key = DerToRsa($der); - return $key; -} - diff --git a/include/crypto.php b/include/crypto.php new file mode 100644 index 000000000..1ab9e7b25 --- /dev/null +++ b/include/crypto.php @@ -0,0 +1,184 @@ +=')) { + openssl_sign($data,$sig,$key,'sha256'); + } + else { + if(strlen($key) < 1024 || extension_loaded('gmp')) { + require_once('library/phpsec/Crypt/RSA.php'); + $rsa = new CRYPT_RSA(); + $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; + $rsa->setHash('sha256'); + $rsa->loadKey($key); + $sig = $rsa->sign($data); + } + else { + logger('rsa_sign: insecure algorithm used. Please upgrade PHP to 5.3'); + openssl_private_encrypt(hex2bin('3031300d060960864801650304020105000420') . hash('sha256',$data,true), $sig, $key); + } + } + return $sig; +} + +function rsa_verify($data,$sig,$key) { + + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + $verify = openssl_verify($data,$sig,$key,'sha256'); + } + else { + if(strlen($key) <= 300 || extension_loaded('gmp')) { + require_once('library/phpsec/Crypt/RSA.php'); + $rsa = new CRYPT_RSA(); + $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; + $rsa->setHash('sha256'); + $rsa->loadKey($key); + $verify = $rsa->verify($data,$sig); + } + else { + // fallback sha256 verify for PHP < 5.3 and large key lengths + $rawsig = ''; + openssl_public_decrypt($sig,$rawsig,$key); + $verify = (($rawsig && substr($rawsig,-32) === hash('sha256',$data,true)) ? true : false); + } + } + return $verify; +} + + +function DerToPem($Der, $Private=false) +{ + //Encode: + $Der = base64_encode($Der); + //Split lines: + $lines = str_split($Der, 65); + $body = implode("\n", $lines); + //Get title: + $title = $Private? 'RSA PRIVATE KEY' : 'PUBLIC KEY'; + //Add wrapping: + $result = "-----BEGIN {$title}-----\n"; + $result .= $body . "\n"; + $result .= "-----END {$title}-----\n"; + + return $result; +} + +function DerToRsa($Der) +{ + //Encode: + $Der = base64_encode($Der); + //Split lines: + $lines = str_split($Der, 65); + $body = implode("\n", $lines); + //Get title: + $title = 'RSA PUBLIC KEY'; + //Add wrapping: + $result = "-----BEGIN {$title}-----\n"; + $result .= $body . "\n"; + $result .= "-----END {$title}-----\n"; + + return $result; +} + + +function pkcs8_encode($Modulus,$PublicExponent) { + //Encode key sequence + $modulus = new ASNValue(ASNValue::TAG_INTEGER); + $modulus->SetIntBuffer($Modulus); + $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); + $publicExponent->SetIntBuffer($PublicExponent); + $keySequenceItems = array($modulus, $publicExponent); + $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); + $keySequence->SetSequence($keySequenceItems); + //Encode bit string + $bitStringValue = $keySequence->Encode(); + $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte + $bitString = new ASNValue(ASNValue::TAG_BITSTRING); + $bitString->Value = $bitStringValue; + //Encode body + $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode(); + $body = new ASNValue(ASNValue::TAG_SEQUENCE); + $body->Value = $bodyValue; + //Get DER encoded public key: + $PublicDER = $body->Encode(); + return $PublicDER; +} + + +function pkcs1_encode($Modulus,$PublicExponent) { + //Encode key sequence + $modulus = new ASNValue(ASNValue::TAG_INTEGER); + $modulus->SetIntBuffer($Modulus); + $publicExponent = new ASNValue(ASNValue::TAG_INTEGER); + $publicExponent->SetIntBuffer($PublicExponent); + $keySequenceItems = array($modulus, $publicExponent); + $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE); + $keySequence->SetSequence($keySequenceItems); + //Encode bit string + $bitStringValue = $keySequence->Encode(); + return $bitStringValue; +} + + +function metopem($m,$e) { + $der = pkcs8_encode($m,$e); + $key = DerToPem($der,false); + return $key; +} + + +function pubrsatome($key,&$m,&$e) { + require_once('library/asn1.php'); + require_once('include/salmon.php'); + + $lines = explode("\n",$key); + unset($lines[0]); + unset($lines[count($lines)]); + $x = base64_decode(implode('',$lines)); + + $r = ASN_BASE::parseASNString($x); + + $m = base64url_decode($r[0]->asnData[0]->asnData); + $e = base64url_decode($r[0]->asnData[1]->asnData); +} + + +function rsatopem($key) { + pubrsatome($key,$m,$e); + return(metopem($m,$e)); +} + +function pemtorsa($key) { + pemtome($key,$m,$e); + return(metorsa($m,$e)); +} + +function pemtome($key,&$m,&$e) { + require_once('include/salmon.php'); + $lines = explode("\n",$key); + unset($lines[0]); + unset($lines[count($lines)]); + $x = base64_decode(implode('',$lines)); + + $r = ASN_BASE::parseASNString($x); + + $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); + $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); +} + +function metorsa($m,$e) { + $der = pkcs1_encode($m,$e); + $key = DerToRsa($der); + return $key; +} + +function salmon_key($pubkey) { + pemtome($pubkey,$m,$e); + return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ; +} diff --git a/include/diaspora.php b/include/diaspora.php index d25137bf3..e39617aa3 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -1,6 +1,6 @@ =')) { - $verify = openssl_verify($signed_data,$signature,$key,'sha256'); - } - else { - // fallback sha256 verify for PHP < 5.3 - $rawsig = ''; - $hash = hash('sha256',$signed_data,true); - openssl_public_decrypt($signature,$rawsig,$key); - $verify = (($rawsig && substr($rawsig,-32) === $hash) ? true : false); - } + $verify = rsa_verify($signed_data,$signature,$key); if(! $verify) { logger('mod-diaspora: Message did not verify. Discarding.'); - receive_return(400); + http_status_exit(400); } logger('mod-diaspora: Message verified.'); diff --git a/include/network.php b/include/network.php index 48e830e84..ddfc34977 100644 --- a/include/network.php +++ b/include/network.php @@ -181,6 +181,20 @@ function xml_status($st, $message = '') { }} +if(! function_exists('http_status_exit')) { +function http_status_exit($val) { + + if($val >= 400) + $err = 'Error'; + if($val >= 200 && $val < 300) + $err = 'OK'; + + logger('http_status_exit ' . $val); + header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err); + killme(); + +}} + // convert an XML document to a normalised, case-corrected array // used by webfinger diff --git a/include/salmon.php b/include/salmon.php index 3ccae2756..4043b4f1d 100644 --- a/include/salmon.php +++ b/include/salmon.php @@ -1,21 +1,7 @@ asnData[1]->asnData[0]->asnData[0]->asnData; - $e = $r[0]->asnData[1]->asnData[0]->asnData[1]->asnData; - - - return 'RSA' . '.' . $m . '.' . $e ; -} function get_salmon_key($uri,$keyhash) { @@ -112,24 +98,15 @@ EOT; $algorithm = 'RSA-SHA256'; $keyhash = base64url_encode(hash('sha256',salmon_key($owner['spubkey'])),true); - // Setup RSA stuff to PKCS#1 sign the data - - require_once('library/phpsec/Crypt/RSA.php'); - - $rsa = new CRYPT_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash('sha256'); - $rsa->loadKey($owner['sprvkey']); - // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; - $signature = base64url_encode($rsa->sign(str_replace('=','',$data . $precomputed),true)); + $signature = base64url_encode(rsa_sign(str_replace('=','',$data . $precomputed),true),$owner['sprvkey']); - $signature2 = base64url_encode($rsa->sign($data . $precomputed)); + $signature2 = base64url_encode(rsa_sign($data . $precomputed),$owner['sprvkey']); - $signature3 = base64url_encode($rsa->sign($data)); + $signature3 = base64url_encode(rsa_sign($data),$owner['sprvkey']); $salmon_tpl = get_markup_template('magicsig.tpl'); diff --git a/include/text.php b/include/text.php index adc94b458..7b43cd340 100644 --- a/include/text.php +++ b/include/text.php @@ -671,7 +671,7 @@ function smilies($s) { $a = get_app(); return str_replace( - array( '<3', '</3', '<\\3', ':-)', ':)', ';-)', ':-(', ':(', ':-P', ':P', ':-"', ':-x', ':-X', ':-D', '8-|', '8-O'), + array( '<3', '</3', '<\\3', ':-)', ':)', ';-)', ':-(', ':(', ':-P', ':P', ':-"', ':-x', ':-X', ':-D', '8-|', '8-O', '~friendika' ), array( '<3', '</3', @@ -688,7 +688,9 @@ function smilies($s) { ':-X', ':-D', '8-|', - '8-O' + '8-O', + '~friendika ~friendika', + ), $s); }} diff --git a/mod/receive.php b/mod/receive.php index 851437124..e2c110202 100644 --- a/mod/receive.php +++ b/mod/receive.php @@ -6,7 +6,7 @@ require_once('include/salmon.php'); -require_once('include/certfns.php'); +require_once('include/crypto.php'); require_once('include/diaspora.php'); diff --git a/mod/salmon.php b/mod/salmon.php index 514653be3..0264e820d 100644 --- a/mod/salmon.php +++ b/mod/salmon.php @@ -5,6 +5,7 @@ // complicated process to try and sort out. require_once('include/salmon.php'); +require_once('include/crypto.php'); require_once('library/simplepie/simplepie.inc'); function salmon_return($val) { @@ -33,7 +34,7 @@ function salmon_post(&$a) { dbesc($nick) ); if(! count($r)) - salmon_return(500); + http_status_exit(500); $importer = $r[0]; @@ -52,7 +53,7 @@ function salmon_post(&$a) { if(! $base) { logger('mod-salmon: unable to locate salmon data in xml '); - salmon_return(400); + http_status_exit(400); } // Stash the signature away for now. We have to find their key or it won't be good for anything. @@ -117,7 +118,7 @@ function salmon_post(&$a) { if(! $author_link) { logger('mod-salmon: Could not retrieve author URI.'); - salmon_return(400); + http_status_exit(400); } // Once we have the author URI, go to the web and try to find their public key @@ -129,54 +130,35 @@ function salmon_post(&$a) { if(! $key) { logger('mod-salmon: Could not retrieve author key.'); - salmon_return(400); + http_status_exit(400); } - // Setup RSA stuff to verify the signature - - require_once('library/phpsec/Crypt/RSA.php'); - - $rsa = new CRYPT_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash('sha256'); - $rsa->loadKey($prvkey); - - $sig = $rsa->sign($data); - - require_once('library/phpsec/Crypt/RSA.php'); - $key_info = explode('.',$key); $m = base64url_decode($key_info[1]); $e = base64url_decode($key_info[2]); - logger('mod-salmon: key details: ' . print_r($key_info,true)); - - $rsa = new CRYPT_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash('sha256'); + logger('mod-salmon: key details: ' . print_r($key_info,true), LOGGER_DEBUG); - $rsa->modulus = new Math_BigInteger($m, 256); - $rsa->k = strlen($rsa->modulus->toBytes()); - $rsa->exponent = new Math_BigInteger($e, 256); + $pubkey = metopem($m,$e); // We should have everything we need now. Let's see if it verifies. - $verify = $rsa->verify($compliant_format,$signature); + $verify = rsa_verify($compliant_format,$signature,$pubkey); if(! $verify) { logger('mod-salmon: message did not verify using protocol. Trying padding hack.'); - $verify = $rsa->verify($signed_data,$signature); + $verify = rsa_verify($signed_data,$signature,$pubkey); } if(! $verify) { logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.'); - $verify = $rsa->verify($stnet_signed_data,$signature); + $verify = rsa_verify($stnet_signed_data,$signature,$pubkey); } if(! $verify) { logger('mod-salmon: Message did not verify. Discarding.'); - salmon_return(400); + http_status_exit(400); } logger('mod-salmon: Message verified.'); @@ -203,7 +185,7 @@ function salmon_post(&$a) { if((count($r)) && (($r[0]['readonly']) || ($r[0]['rel'] == CONTACT_IS_FOLLOWER) || ($r[0]['blocked']))) { logger('mod-salmon: Ignoring this author.'); - salmon_return(202); + http_status_exit(202); // NOTREACHED } @@ -225,7 +207,7 @@ function salmon_post(&$a) { consume_feed($feedxml,$importer,$contact_rec,$hub); - salmon_return(200); + http_status_exit(200); } diff --git a/mod/xrd.php b/mod/xrd.php index 9021222b7..fcec74336 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -1,9 +1,8 @@ $a->get_baseurl(), @@ -41,7 +38,6 @@ function xrd_content(&$a) { else $dspr = ''; - $tpl = file_get_contents('view/xrd_person.tpl'); $o = replace_macros($tpl, array( @@ -60,7 +56,7 @@ function xrd_content(&$a) { $arr = array('user' => $r[0], 'xml' => $o); call_hooks('personal_xrd', $arr); - echo $o; + echo $arr['xml']; killme(); } -- cgit v1.2.3