]> git.mxchange.org Git - friendica-addons.git/blob - securemail/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
securemail: update pgp library
[friendica-addons.git] / securemail / vendor / phpseclib / phpseclib / phpseclib / System / SSH / Agent.php
1 <?php
2 /**
3  * Pure-PHP ssh-agent client.
4  *
5  * PHP versions 4 and 5
6  *
7  * Here are some examples of how to use this library:
8  * <code>
9  * <?php
10  *    include 'System/SSH/Agent.php';
11  *    include 'Net/SSH2.php';
12  *
13  *    $agent = new System_SSH_Agent();
14  *
15  *    $ssh = new Net_SSH2('www.domain.tld');
16  *    if (!$ssh->login('username', $agent)) {
17  *        exit('Login Failed');
18  *    }
19  *
20  *    echo $ssh->exec('pwd');
21  *    echo $ssh->exec('ls -la');
22  * ?>
23  * </code>
24  *
25  * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
26  * of this software and associated documentation files (the "Software"), to deal
27  * in the Software without restriction, including without limitation the rights
28  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29  * copies of the Software, and to permit persons to whom the Software is
30  * furnished to do so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice shall be included in
33  * all copies or substantial portions of the Software.
34  *
35  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41  * THE SOFTWARE.
42  *
43  * @category  System
44  * @package   System_SSH_Agent
45  * @author    Jim Wigginton <terrafrost@php.net>
46  * @copyright 2014 Jim Wigginton
47  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
48  * @link      http://phpseclib.sourceforge.net
49  * @internal  See http://api.libssh.org/rfc/PROTOCOL.agent
50  */
51
52 /**#@+
53  * Message numbers
54  *
55  * @access private
56  */
57 // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
58 define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
59 // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
60 define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
61 define('SYSTEM_SSH_AGENT_FAILURE', 5);
62 // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
63 define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
64 // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
65 define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
66 /**#@-*/
67
68 /**
69  * Pure-PHP ssh-agent client identity object
70  *
71  * Instantiation should only be performed by System_SSH_Agent class.
72  * This could be thought of as implementing an interface that Crypt_RSA
73  * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
74  * The methods in this interface would be getPublicKey, setSignatureMode
75  * and sign since those are the methods phpseclib looks for to perform
76  * public key authentication.
77  *
78  * @package System_SSH_Agent
79  * @author  Jim Wigginton <terrafrost@php.net>
80  * @access  internal
81  */
82 class System_SSH_Agent_Identity
83 {
84     /**
85      * Key Object
86      *
87      * @var Crypt_RSA
88      * @access private
89      * @see System_SSH_Agent_Identity::getPublicKey()
90      */
91     var $key;
92
93     /**
94      * Key Blob
95      *
96      * @var String
97      * @access private
98      * @see System_SSH_Agent_Identity::sign()
99      */
100     var $key_blob;
101
102     /**
103      * Socket Resource
104      *
105      * @var Resource
106      * @access private
107      * @see System_SSH_Agent_Identity::sign()
108      */
109     var $fsock;
110
111     /**
112      * Default Constructor.
113      *
114      * @param Resource $fsock
115      * @return System_SSH_Agent_Identity
116      * @access private
117      */
118     function System_SSH_Agent_Identity($fsock)
119     {
120         $this->fsock = $fsock;
121     }
122
123     /**
124      * Set Public Key
125      *
126      * Called by System_SSH_Agent::requestIdentities()
127      *
128      * @param Crypt_RSA $key
129      * @access private
130      */
131     function setPublicKey($key)
132     {
133         $this->key = $key;
134         $this->key->setPublicKey();
135     }
136
137     /**
138      * Set Public Key
139      *
140      * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
141      * but this saves a small amount of computation.
142      *
143      * @param String $key_blob
144      * @access private
145      */
146     function setPublicKeyBlob($key_blob)
147     {
148         $this->key_blob = $key_blob;
149     }
150
151     /**
152      * Get Public Key
153      *
154      * Wrapper for $this->key->getPublicKey()
155      *
156      * @param Integer $format optional
157      * @return Mixed
158      * @access public
159      */
160     function getPublicKey($format = null)
161     {
162         return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
163     }
164
165     /**
166      * Set Signature Mode
167      *
168      * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
169      * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
170      *
171      * @param Integer $mode
172      * @access public
173      */
174     function setSignatureMode($mode)
175     {
176     }
177
178     /**
179      * Create a signature
180      *
181      * See "2.6.2 Protocol 2 private key signature request"
182      *
183      * @param String $message
184      * @return String
185      * @access public
186      */
187     function sign($message)
188     {
189         // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
190         $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
191         $packet = pack('Na*', strlen($packet), $packet);
192         if (strlen($packet) != fputs($this->fsock, $packet)) {
193             user_error('Connection closed during signing');
194         }
195
196         $length = current(unpack('N', fread($this->fsock, 4)));
197         $type = ord(fread($this->fsock, 1));
198         if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
199             user_error('Unable to retreive signature');
200         }
201
202         $signature_blob = fread($this->fsock, $length - 1);
203         // the only other signature format defined - ssh-dss - is the same length as ssh-rsa
204         // the + 12 is for the other various SSH added length fields
205         return substr($signature_blob, strlen('ssh-rsa') + 12);
206     }
207 }
208
209 /**
210  * Pure-PHP ssh-agent client identity factory
211  *
212  * requestIdentities() method pumps out System_SSH_Agent_Identity objects
213  *
214  * @package System_SSH_Agent
215  * @author  Jim Wigginton <terrafrost@php.net>
216  * @access  internal
217  */
218 class System_SSH_Agent
219 {
220     /**
221      * Socket Resource
222      *
223      * @var Resource
224      * @access private
225      */
226     var $fsock;
227
228     /**
229      * Default Constructor
230      *
231      * @return System_SSH_Agent
232      * @access public
233      */
234     function System_SSH_Agent()
235     {
236         switch (true) {
237             case isset($_SERVER['SSH_AUTH_SOCK']):
238                 $address = $_SERVER['SSH_AUTH_SOCK'];
239                 break;
240             case isset($_ENV['SSH_AUTH_SOCK']):
241                 $address = $_ENV['SSH_AUTH_SOCK'];
242                 break;
243             default:
244                 user_error('SSH_AUTH_SOCK not found');
245                 return false;
246         }
247
248         $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
249         if (!$this->fsock) {
250             user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
251         }
252     }
253
254     /**
255      * Request Identities
256      *
257      * See "2.5.2 Requesting a list of protocol 2 keys"
258      * Returns an array containing zero or more System_SSH_Agent_Identity objects
259      *
260      * @return Array
261      * @access public
262      */
263     function requestIdentities()
264     {
265         if (!$this->fsock) {
266             return array();
267         }
268
269         $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
270         if (strlen($packet) != fputs($this->fsock, $packet)) {
271             user_error('Connection closed while requesting identities');
272         }
273
274         $length = current(unpack('N', fread($this->fsock, 4)));
275         $type = ord(fread($this->fsock, 1));
276         if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
277             user_error('Unable to request identities');
278         }
279
280         $identities = array();
281         $keyCount = current(unpack('N', fread($this->fsock, 4)));
282         for ($i = 0; $i < $keyCount; $i++) {
283             $length = current(unpack('N', fread($this->fsock, 4)));
284             $key_blob = fread($this->fsock, $length);
285             $length = current(unpack('N', fread($this->fsock, 4)));
286             $key_comment = fread($this->fsock, $length);
287             $length = current(unpack('N', substr($key_blob, 0, 4)));
288             $key_type = substr($key_blob, 4, $length);
289             switch ($key_type) {
290                 case 'ssh-rsa':
291                     if (!class_exists('Crypt_RSA')) {
292                         include_once 'Crypt/RSA.php';
293                     }
294                     $key = new Crypt_RSA();
295                     $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment);
296                     break;
297                 case 'ssh-dss':
298                     // not currently supported
299                     break;
300             }
301             // resources are passed by reference by default
302             if (isset($key)) {
303                 $identity = new System_SSH_Agent_Identity($this->fsock);
304                 $identity->setPublicKey($key);
305                 $identity->setPublicKeyBlob($key_blob);
306                 $identities[] = $identity;
307                 unset($key);
308             }
309         }
310
311         return $identities;
312     }
313 }