[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body