[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/ -> PSS.php (source)

   1  <?php
   2  
   3  /**
   4   * PKCS#8 Formatted RSA-PSS Key Handler
   5   *
   6   * PHP version 5
   7   *
   8   * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
   9   *
  10   * Processes keys with the following headers:
  11   *
  12   * -----BEGIN ENCRYPTED PRIVATE KEY-----
  13   * -----BEGIN PRIVATE KEY-----
  14   * -----BEGIN PUBLIC KEY-----
  15   *
  16   * Analogous to "openssl genpkey -algorithm rsa-pss".
  17   *
  18   * @author    Jim Wigginton <terrafrost@php.net>
  19   * @copyright 2015 Jim Wigginton
  20   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  21   * @link      http://phpseclib.sourceforge.net
  22   */
  23  
  24  namespace phpseclib3\Crypt\RSA\Formats\Keys;
  25  
  26  use phpseclib3\Common\Functions\Strings;
  27  use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
  28  use phpseclib3\File\ASN1;
  29  use phpseclib3\File\ASN1\Maps;
  30  use phpseclib3\Math\BigInteger;
  31  
  32  /**
  33   * PKCS#8 Formatted RSA-PSS Key Handler
  34   *
  35   * @author  Jim Wigginton <terrafrost@php.net>
  36   */
  37  abstract class PSS extends Progenitor
  38  {
  39      /**
  40       * OID Name
  41       *
  42       * @var string
  43       */
  44      const OID_NAME = 'id-RSASSA-PSS';
  45  
  46      /**
  47       * OID Value
  48       *
  49       * @var string
  50       */
  51      const OID_VALUE = '1.2.840.113549.1.1.10';
  52  
  53      /**
  54       * OIDs loaded
  55       *
  56       * @var bool
  57       */
  58      private static $oidsLoaded = false;
  59  
  60      /**
  61       * Child OIDs loaded
  62       *
  63       * @var bool
  64       */
  65      protected static $childOIDsLoaded = false;
  66  
  67      /**
  68       * Initialize static variables
  69       */
  70      private static function initialize_static_variables()
  71      {
  72          if (!self::$oidsLoaded) {
  73              ASN1::loadOIDs([
  74                  'md2' => '1.2.840.113549.2.2',
  75                  'md4' => '1.2.840.113549.2.4',
  76                  'md5' => '1.2.840.113549.2.5',
  77                  'id-sha1' => '1.3.14.3.2.26',
  78                  'id-sha256' => '2.16.840.1.101.3.4.2.1',
  79                  'id-sha384' => '2.16.840.1.101.3.4.2.2',
  80                  'id-sha512' => '2.16.840.1.101.3.4.2.3',
  81                  'id-sha224' => '2.16.840.1.101.3.4.2.4',
  82                  'id-sha512/224' => '2.16.840.1.101.3.4.2.5',
  83                  'id-sha512/256' => '2.16.840.1.101.3.4.2.6',
  84  
  85                  'id-mgf1' => '1.2.840.113549.1.1.8'
  86              ]);
  87              self::$oidsLoaded = true;
  88          }
  89      }
  90  
  91      /**
  92       * Break a public or private key down into its constituent components
  93       *
  94       * @param string $key
  95       * @param string $password optional
  96       * @return array
  97       */
  98      public static function load($key, $password = '')
  99      {
 100          self::initialize_static_variables();
 101  
 102          if (!Strings::is_stringable($key)) {
 103              throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
 104          }
 105  
 106          $components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false];
 107  
 108          $key = parent::load($key, $password);
 109  
 110          $type = isset($key['privateKey']) ? 'private' : 'public';
 111  
 112          $result = $components + PKCS1::load($key[$type . 'Key']);
 113  
 114          if (isset($key[$type . 'KeyAlgorithm']['parameters'])) {
 115              $decoded = ASN1::decodeBER($key[$type . 'KeyAlgorithm']['parameters']);
 116              if ($decoded === false) {
 117                  throw new \UnexpectedValueException('Unable to decode parameters');
 118              }
 119              $params = ASN1::asn1map($decoded[0], Maps\RSASSA_PSS_params::MAP);
 120          } else {
 121              $params = [];
 122          }
 123  
 124          if (isset($params['maskGenAlgorithm']['parameters'])) {
 125              $decoded = ASN1::decodeBER($params['maskGenAlgorithm']['parameters']);
 126              if ($decoded === false) {
 127                  throw new \UnexpectedValueException('Unable to decode parameters');
 128              }
 129              $params['maskGenAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], Maps\HashAlgorithm::MAP);
 130          } else {
 131              $params['maskGenAlgorithm'] = [
 132                  'algorithm' => 'id-mgf1',
 133                  'parameters' => ['algorithm' => 'id-sha1']
 134              ];
 135          }
 136  
 137          if (!isset($params['hashAlgorithm']['algorithm'])) {
 138              $params['hashAlgorithm']['algorithm'] = 'id-sha1';
 139          }
 140  
 141          $result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']);
 142          $result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']);
 143          if (isset($params['saltLength'])) {
 144              $result['saltLength'] = (int) $params['saltLength']->toString();
 145          }
 146  
 147          if (isset($key['meta'])) {
 148              $result['meta'] = $key['meta'];
 149          }
 150  
 151          return $result;
 152      }
 153  
 154      /**
 155       * Convert a private key to the appropriate format.
 156       *
 157       * @param \phpseclib3\Math\BigInteger $n
 158       * @param \phpseclib3\Math\BigInteger $e
 159       * @param \phpseclib3\Math\BigInteger $d
 160       * @param array $primes
 161       * @param array $exponents
 162       * @param array $coefficients
 163       * @param string $password optional
 164       * @param array $options optional
 165       * @return string
 166       */
 167      public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
 168      {
 169          self::initialize_static_variables();
 170  
 171          $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
 172          $key = ASN1::extractBER($key);
 173          $params = self::savePSSParams($options);
 174          return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
 175      }
 176  
 177      /**
 178       * Convert a public key to the appropriate format
 179       *
 180       * @param \phpseclib3\Math\BigInteger $n
 181       * @param \phpseclib3\Math\BigInteger $e
 182       * @param array $options optional
 183       * @return string
 184       */
 185      public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
 186      {
 187          self::initialize_static_variables();
 188  
 189          $key = PKCS1::savePublicKey($n, $e);
 190          $key = ASN1::extractBER($key);
 191          $params = self::savePSSParams($options);
 192          return self::wrapPublicKey($key, $params);
 193      }
 194  
 195      /**
 196       * Encodes PSS parameters
 197       *
 198       * @param array $options
 199       * @return string
 200       */
 201      public static function savePSSParams(array $options)
 202      {
 203          /*
 204           The trailerField field is an integer.  It provides
 205           compatibility with IEEE Std 1363a-2004 [P1363A].  The value
 206           MUST be 1, which represents the trailer field with hexadecimal
 207           value 0xBC.  Other trailer fields, including the trailer field
 208           composed of HashID concatenated with 0xCC that is specified in
 209           IEEE Std 1363a, are not supported.  Implementations that
 210           perform signature generation MUST omit the trailerField field,
 211           indicating that the default trailer field value was used.
 212           Implementations that perform signature validation MUST
 213           recognize both a present trailerField field with value 1 and an
 214           absent trailerField field.
 215  
 216           source: https://tools.ietf.org/html/rfc4055#page-9
 217          */
 218          $params = [
 219              'trailerField' => new BigInteger(1)
 220          ];
 221          if (isset($options['hash'])) {
 222              $params['hashAlgorithm']['algorithm'] = 'id-' . $options['hash'];
 223          }
 224          if (isset($options['MGFHash'])) {
 225              $temp = ['algorithm' => 'id-' . $options['MGFHash']];
 226              $temp = ASN1::encodeDER($temp, Maps\HashAlgorithm::MAP);
 227              $params['maskGenAlgorithm'] = [
 228                  'algorithm' => 'id-mgf1',
 229                  'parameters' => new ASN1\Element($temp)
 230              ];
 231          }
 232          if (isset($options['saltLength'])) {
 233              $params['saltLength'] = new BigInteger($options['saltLength']);
 234          }
 235  
 236          return new ASN1\Element(ASN1::encodeDER($params, Maps\RSASSA_PSS_params::MAP));
 237      }
 238  }