Subversion Repositories oidplus

Rev

Rev 846 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /**
  4.  * XML Formatted RSA Key Handler
  5.  *
  6.  * More info:
  7.  *
  8.  * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
  9.  * http://www.w3.org/TR/xkms2/#XKMS_2_0_Paragraph_269
  10.  * http://en.wikipedia.org/wiki/XML_Signature
  11.  * http://en.wikipedia.org/wiki/XKMS
  12.  *
  13.  * PHP version 5
  14.  *
  15.  * @category  Crypt
  16.  * @package   RSA
  17.  * @author    Jim Wigginton <terrafrost@php.net>
  18.  * @copyright 2015 Jim Wigginton
  19.  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  20.  * @link      http://phpseclib.sourceforge.net
  21.  */
  22.  
  23. namespace phpseclib3\Crypt\RSA\Formats\Keys;
  24.  
  25. use ParagonIE\ConstantTime\Base64;
  26. use phpseclib3\Common\Functions\Strings;
  27. use phpseclib3\Exception\BadConfigurationException;
  28. use phpseclib3\Exception\UnsupportedFormatException;
  29. use phpseclib3\Math\BigInteger;
  30.  
  31. /**
  32.  * XML Formatted RSA Key Handler
  33.  *
  34.  * @package RSA
  35.  * @author  Jim Wigginton <terrafrost@php.net>
  36.  * @access  public
  37.  */
  38. abstract class XML
  39. {
  40.     /**
  41.      * Break a public or private key down into its constituent components
  42.      *
  43.      * @access public
  44.      * @param string $key
  45.      * @param string $password optional
  46.      * @return array
  47.      */
  48.     public static function load($key, $password = '')
  49.     {
  50.         if (!Strings::is_stringable($key)) {
  51.             throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
  52.         }
  53.  
  54.         if (!class_exists('DOMDocument')) {
  55.             throw new BadConfigurationException('The dom extension is not setup correctly on this system');
  56.         }
  57.  
  58.         $components = [
  59.             'isPublicKey' => false,
  60.             'primes' => [],
  61.             'exponents' => [],
  62.             'coefficients' => []
  63.         ];
  64.  
  65.         $use_errors = libxml_use_internal_errors(true);
  66.  
  67.         $dom = new \DOMDocument();
  68.         if (substr($key, 0, 5) != '<?xml') {
  69.             $key = '<xml>' . $key . '</xml>';
  70.         }
  71.         if (!$dom->loadXML($key)) {
  72.             libxml_use_internal_errors($use_errors);
  73.             throw new \UnexpectedValueException('Key does not appear to contain XML');
  74.         }
  75.         $xpath = new \DOMXPath($dom);
  76.         $keys = ['modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd'];
  77.         foreach ($keys as $key) {
  78.             // $dom->getElementsByTagName($key) is case-sensitive
  79.             $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
  80.             if (!$temp->length) {
  81.                 continue;
  82.             }
  83.             $value = new BigInteger(Base64::decode($temp->item(0)->nodeValue), 256);
  84.             switch ($key) {
  85.                 case 'modulus':
  86.                     $components['modulus'] = $value;
  87.                     break;
  88.                 case 'exponent':
  89.                     $components['publicExponent'] = $value;
  90.                     break;
  91.                 case 'p':
  92.                     $components['primes'][1] = $value;
  93.                     break;
  94.                 case 'q':
  95.                     $components['primes'][2] = $value;
  96.                     break;
  97.                 case 'dp':
  98.                     $components['exponents'][1] = $value;
  99.                     break;
  100.                 case 'dq':
  101.                     $components['exponents'][2] = $value;
  102.                     break;
  103.                 case 'inverseq':
  104.                     $components['coefficients'][2] = $value;
  105.                     break;
  106.                 case 'd':
  107.                     $components['privateExponent'] = $value;
  108.             }
  109.         }
  110.  
  111.         libxml_use_internal_errors($use_errors);
  112.  
  113.         foreach ($components as $key => $value) {
  114.             if (is_array($value) && !count($value)) {
  115.                 unset($components[$key]);
  116.             }
  117.         }
  118.  
  119.         if (isset($components['modulus']) && isset($components['publicExponent'])) {
  120.             if (count($components) == 3) {
  121.                 $components['isPublicKey'] = true;
  122.             }
  123.             return $components;
  124.         }
  125.  
  126.         throw new \UnexpectedValueException('Modulus / exponent not present');
  127.     }
  128.  
  129.     /**
  130.      * Convert a private key to the appropriate format.
  131.      *
  132.      * @access public
  133.      * @param \phpseclib3\Math\BigInteger $n
  134.      * @param \phpseclib3\Math\BigInteger $e
  135.      * @param \phpseclib3\Math\BigInteger $d
  136.      * @param array $primes
  137.      * @param array $exponents
  138.      * @param array $coefficients
  139.      * @param string $password optional
  140.      * @return string
  141.      */
  142.     public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '')
  143.     {
  144.         if (count($primes) != 2) {
  145.             throw new \InvalidArgumentException('XML does not support multi-prime RSA keys');
  146.         }
  147.  
  148.         if (!empty($password) && is_string($password)) {
  149.             throw new UnsupportedFormatException('XML private keys do not support encryption');
  150.         }
  151.  
  152.         return "<RSAKeyPair>\r\n" .
  153.                '  <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
  154.                '  <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
  155.                '  <P>' . Base64::encode($primes[1]->toBytes()) . "</P>\r\n" .
  156.                '  <Q>' . Base64::encode($primes[2]->toBytes()) . "</Q>\r\n" .
  157.                '  <DP>' . Base64::encode($exponents[1]->toBytes()) . "</DP>\r\n" .
  158.                '  <DQ>' . Base64::encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
  159.                '  <InverseQ>' . Base64::encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
  160.                '  <D>' . Base64::encode($d->toBytes()) . "</D>\r\n" .
  161.                '</RSAKeyPair>';
  162.     }
  163.  
  164.     /**
  165.      * Convert a public key to the appropriate format
  166.      *
  167.      * @access public
  168.      * @param \phpseclib3\Math\BigInteger $n
  169.      * @param \phpseclib3\Math\BigInteger $e
  170.      * @return string
  171.      */
  172.     public static function savePublicKey(BigInteger $n, BigInteger $e)
  173.     {
  174.         return "<RSAKeyValue>\r\n" .
  175.                '  <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
  176.                '  <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
  177.                '</RSAKeyValue>';
  178.     }
  179. }
  180.