1<?php
2
3/**
4 * PKCS#8 Formatted RSA 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 ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
17 * is specific to private keys it's basically creating a DER-encoded wrapper
18 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
19 *
20 * @category  Crypt
21 * @package   RSA
22 * @author    Jim Wigginton <terrafrost@php.net>
23 * @copyright 2015 Jim Wigginton
24 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
25 * @link      http://phpseclib.sourceforge.net
26 */
27
28namespace phpseclib3\Crypt\RSA\Formats\Keys;
29
30use phpseclib3\Common\Functions\Strings;
31use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
32use phpseclib3\File\ASN1;
33use phpseclib3\Math\BigInteger;
34
35/**
36 * PKCS#8 Formatted RSA Key Handler
37 *
38 * @package RSA
39 * @author  Jim Wigginton <terrafrost@php.net>
40 * @access  public
41 */
42abstract class PKCS8 extends Progenitor
43{
44    /**
45     * OID Name
46     *
47     * @var string
48     * @access private
49     */
50    const OID_NAME = 'rsaEncryption';
51
52    /**
53     * OID Value
54     *
55     * @var string
56     * @access private
57     */
58    const OID_VALUE = '1.2.840.113549.1.1.1';
59
60    /**
61     * Child OIDs loaded
62     *
63     * @var bool
64     * @access private
65     */
66    protected static $childOIDsLoaded = false;
67
68    /**
69     * Break a public or private key down into its constituent components
70     *
71     * @access public
72     * @param string $key
73     * @param string $password optional
74     * @return array
75     */
76    public static function load($key, $password = '')
77    {
78        if (!Strings::is_stringable($key)) {
79            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
80        }
81
82        if (strpos($key, 'PUBLIC') !== false) {
83            $components = ['isPublicKey' => true];
84        } elseif (strpos($key, 'PRIVATE') !== false) {
85            $components = ['isPublicKey' => false];
86        } else {
87            $components = [];
88        }
89
90        $key = parent::load($key, $password);
91
92        if (isset($key['privateKey'])) {
93            if (!isset($components['isPublicKey'])) {
94                $components['isPublicKey'] = false;
95            }
96            $type = 'private';
97        } else {
98            if (!isset($components['isPublicKey'])) {
99                $components['isPublicKey'] = true;
100            }
101            $type = 'public';
102        }
103
104        $result = $components + PKCS1::load($key[$type . 'Key']);
105
106        if (isset($key['meta'])) {
107            $result['meta'] = $key['meta'];
108        }
109
110        return $result;
111    }
112
113    /**
114     * Convert a private key to the appropriate format.
115     *
116     * @access public
117     * @param \phpseclib3\Math\BigInteger $n
118     * @param \phpseclib3\Math\BigInteger $e
119     * @param \phpseclib3\Math\BigInteger $d
120     * @param array $primes
121     * @param array $exponents
122     * @param array $coefficients
123     * @param string $password optional
124     * @param array $options optional
125     * @return string
126     */
127    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
128    {
129        $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
130        $key = ASN1::extractBER($key);
131        return self::wrapPrivateKey($key, [], null, $password, null, '', $options);
132    }
133
134    /**
135     * Convert a public key to the appropriate format
136     *
137     * @access public
138     * @param \phpseclib3\Math\BigInteger $n
139     * @param \phpseclib3\Math\BigInteger $e
140     * @param array $options optional
141     * @return string
142     */
143    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
144    {
145        $key = PKCS1::savePublicKey($n, $e);
146        $key = ASN1::extractBER($key);
147        return self::wrapPublicKey($key, null);
148    }
149}
150