56fc344bbc313bbf146eeebb693617fb27b06b4f
[Packages/TYPO3.CMS.git] / typo3 / sysext / rsaauth / Classes / Backend / PhpBackend.php
1 <?php
2 namespace TYPO3\CMS\Rsaauth\Backend;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * This class contains a PHP OpenSSL backend for the TYPO3 RSA authentication
19 * service. See class \TYPO3\CMS\Rsaauth\Backend\AbstractBackend for the information on using
20 * backends.
21 */
22 class PhpBackend extends AbstractBackend
23 {
24 /**
25 * Creates a new key pair for the encryption or gets the existing key pair (if one already has been generated).
26 *
27 * There should only be one key pair per request because the second private key would overwrites the first private
28 * key. So the submitting the form with the first public key would not work anymore.
29 *
30 * @return \TYPO3\CMS\Rsaauth\Keypair|NULL a key pair or NULL in case of error
31 */
32 public function createNewKeyPair()
33 {
34 /** @var $keyPair \TYPO3\CMS\Rsaauth\Keypair */
35 $keyPair = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Rsaauth\Keypair::class);
36 if ($keyPair->isReady()) {
37 return $keyPair;
38 }
39
40 $privateKey = @openssl_pkey_new();
41 if ($privateKey !== false) {
42 // Create private key as string
43 $privateKeyStr = '';
44 openssl_pkey_export($privateKey, $privateKeyStr);
45 // Prepare public key information
46 $exportedData = '';
47 $csr = openssl_csr_new([
48 'localityName' => 'foo',
49 'organizationName' => 'bar',
50 ], $privateKey);
51 openssl_csr_export($csr, $exportedData, false);
52 // Get public key (in fact modulus) and exponent
53 $publicKey = $this->extractPublicKeyModulus($exportedData);
54 $exponent = $this->extractExponent($exportedData);
55
56 $keyPair->setExponent($exponent);
57 $keyPair->setPrivateKey($privateKeyStr);
58 $keyPair->setPublicKey($publicKey);
59 // Clean up all resources
60 openssl_free_key($privateKey);
61 } else {
62 $keyPair = null;
63 }
64
65 return $keyPair;
66 }
67
68 /**
69 * Decrypts data using the private key. This implementation uses PHP OpenSSL
70 * extension.
71 *
72 * @param string $privateKey The private key (obtained from a call to createNewKeyPair())
73 * @param string $data Data to decrypt (base64-encoded)
74 * @return string|NULL Decrypted data or NULL in case of an error
75 * @see \TYPO3\CMS\Rsaauth\Backend\AbstractBackend::decrypt()
76 */
77 public function decrypt($privateKey, $data)
78 {
79 $result = '';
80 if (!@openssl_private_decrypt(base64_decode($data), $result, $privateKey)) {
81 $result = null;
82 }
83 return $result;
84 }
85
86 /**
87 * Checks if this backend is available for calling. In particular checks if
88 * PHP OpenSSl extension is installed and functional.
89 *
90 * @return bool
91 * @see \TYPO3\CMS\Rsaauth\Backend\AbstractBackend::isAvailable()
92 */
93 public function isAvailable()
94 {
95 $result = false;
96 if (is_callable('openssl_pkey_new')) {
97 // PHP extension has to be configured properly. It
98 // can be installed and available but will not work unless
99 // properly configured. So we check if it works.
100 $testKey = @openssl_pkey_new();
101 if (is_resource($testKey)) {
102 openssl_free_key($testKey);
103 $result = true;
104 }
105 }
106 return $result;
107 }
108
109 /**
110 * Extracts the exponent from the OpenSSL CSR
111 *
112 * @param string $data The result of openssl_csr_export()
113 * @return int The exponent as a number
114 */
115 protected function extractExponent($data)
116 {
117 $index = strpos($data, 'Exponent: ');
118 // We do not check for '$index === FALSE' because the exponent is
119 // always there!
120 return (int)substr($data, $index + 10);
121 }
122
123 /**
124 * Extracts public key modulus from the OpenSSL CSR.
125 *
126 * @param string $data The result of openssl_csr_export()
127 * @return string Modulus as uppercase hex string
128 */
129 protected function extractPublicKeyModulus($data)
130 {
131 $fragment = preg_replace('/.*Modulus.*?\\n(.*)Exponent:.*/ms', '\\1', $data);
132 $fragment = preg_replace('/[\\s\\n\\r:]/', '', $fragment);
133 return trim(strtoupper(substr($fragment, 2)));
134 }
135 }