2ef268e178b8fd113536f10e500d8a18fef1c18b
[Packages/TYPO3.CMS.git] / typo3 / sysext / rsaauth / Classes / Backend / CommandLineBackend.php
1 <?php
2 namespace TYPO3\CMS\Rsaauth\Backend;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009-2013 Dmitry Dulepov <dmitry@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28
29 /**
30 * This class contains a OpenSSL backend for the TYPO3 RSA authentication
31 * service. It uses shell version of OpenSSL to perform tasks. See class
32 * \TYPO3\CMS\Rsaauth\Backend\AbstractBackend for the information on using backends.
33 *
34 * @author Dmitry Dulepov <dmitry@typo3.org>
35 */
36 class CommandLineBackend extends \TYPO3\CMS\Rsaauth\Backend\AbstractBackend {
37 /**
38 * @var integer
39 */
40 const DEFAULT_EXPONENT = 65537;
41
42 /**
43 * A path to the openssl binary or FALSE if the binary does not exist
44 *
45 * @var mixed
46 */
47 protected $opensslPath;
48
49 /**
50 * Temporary directory. It is best of it is outside of the web site root and
51 * not publicly readable.
52 * For now we use typo3temp/.
53 *
54 * @var string
55 */
56 protected $temporaryDirectory;
57
58 /**
59 * Creates an instance of this class. It obtains a path to the OpenSSL
60 * binary.
61 */
62 public function __construct() {
63 $this->opensslPath = \TYPO3\CMS\Core\Utility\CommandUtility::getCommand('openssl');
64 $this->temporaryDirectory = PATH_site . 'typo3temp';
65 // Get temporary directory from the configuration
66 $extconf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['rsaauth']);
67 if ($extconf['temporaryDirectory'] != '' && $extconf['temporaryDirectory'][0] == '/' && @is_dir($extconf['temporaryDirectory']) && is_writable($extconf['temporaryDirectory'])) {
68 $this->temporaryDirectory = $extconf['temporaryDirectory'];
69 }
70 }
71
72 /**
73 * Creates a new key pair for the encryption or gets the existing key pair (if one already has been generated).
74 *
75 * There should only be one key pair per request because the second private key would overwrites the first private
76 * key. So the submitting the form with the first public key would not work anymore.
77 *
78 * @return \TYPO3\CMS\Rsaauth\Keypair|NULL a key pair or NULL in case of error
79 */
80 public function createNewKeyPair() {
81 /** @var $keyPair \TYPO3\CMS\Rsaauth\Keypair */
82 $keyPair = GeneralUtility::makeInstance('TYPO3\\CMS\\Rsaauth\\Keypair');
83 if ($keyPair->isReady()) {
84 return $keyPair;
85 }
86
87 if ($this->opensslPath === FALSE) {
88 return NULL;
89 }
90
91 // Create a temporary file. Security: tempnam() sets permissions to 0600
92 $privateKeyFile = tempnam($this->temporaryDirectory, uniqid());
93
94 // Generate the private key.
95 //
96 // PHP generates 1024 bit key files. We force command line version
97 // to do the same and use the F4 (0x10001) exponent. This is the most
98 // secure.
99 $command = $this->opensslPath . ' genrsa -out ' . escapeshellarg($privateKeyFile) . ' 1024';
100 if (TYPO3_OS === 'WIN') {
101 $command .= ' 2>NUL';
102 } else {
103 $command .= ' 2>/dev/null';
104 }
105 \TYPO3\CMS\Core\Utility\CommandUtility::exec($command);
106 // Test that we got a private key
107 $privateKey = file_get_contents($privateKeyFile);
108 if (FALSE !== strpos($privateKey, 'BEGIN RSA PRIVATE KEY')) {
109 // Ok, we got the private key. Get the modulus.
110 $command = $this->opensslPath . ' rsa -noout -modulus -in ' . escapeshellarg($privateKeyFile);
111 $value = \TYPO3\CMS\Core\Utility\CommandUtility::exec($command);
112 if (substr($value, 0, 8) === 'Modulus=') {
113 $publicKey = substr($value, 8);
114
115 $keyPair->setExponent(self::DEFAULT_EXPONENT);
116 $keyPair->setPrivateKey($privateKey);
117 $keyPair->setPublicKey($publicKey);
118 }
119 } else {
120 $keyPair = NULL;
121 }
122
123 @unlink($privateKeyFile);
124 return $keyPair;
125 }
126
127 /**
128 * @param string $privateKey The private key (obtained from a call to createNewKeyPair())
129 * @param string $data Data to decrypt (base64-encoded)
130 * @return string Decrypted data or NULL in case of a error
131 * @see \TYPO3\CMS\Rsaauth\Backend\AbstractBackend::decrypt()
132 */
133 public function decrypt($privateKey, $data) {
134 // Key must be put to the file
135 $privateKeyFile = tempnam($this->temporaryDirectory, uniqid());
136 file_put_contents($privateKeyFile, $privateKey);
137 $dataFile = tempnam($this->temporaryDirectory, uniqid());
138 file_put_contents($dataFile, base64_decode($data));
139 // Prepare the command
140 $command = $this->opensslPath . ' rsautl -inkey ' . escapeshellarg($privateKeyFile) . ' -in ' . escapeshellarg($dataFile) . ' -decrypt';
141 // Execute the command and capture the result
142 $output = array();
143 \TYPO3\CMS\Core\Utility\CommandUtility::exec($command, $output);
144 // Remove the file
145 @unlink($privateKeyFile);
146 @unlink($dataFile);
147 return implode(LF, $output);
148 }
149
150 /**
151 * Checks if command line version of the OpenSSL is available and can be
152 * executed successfully.
153 *
154 * @return void
155 * @see \TYPO3\CMS\Rsaauth\Backend\AbstractBackend::isAvailable()
156 */
157 public function isAvailable() {
158 $result = FALSE;
159 if ($this->opensslPath) {
160 // If path exists, test that command runs and can produce output
161 $test = \TYPO3\CMS\Core\Utility\CommandUtility::exec($this->opensslPath . ' version');
162 $result = substr($test, 0, 8) == 'OpenSSL ';
163 }
164 return $result;
165 }
166
167 }