thomascube
2012-03-03 884add1419729cb8eb5ed8fb47ea68e5f6ce6682
commit | author | age
884add 1 <?php
T 2 /*
3  +-------------------------------------------------------------------------+
4  | GnuPG (PGP) driver for the Enigma Plugin                                |
5  |                                                                         |
6  | This program is free software; you can redistribute it and/or modify    |
7  | it under the terms of the GNU General Public License version 2          |
8  | as published by the Free Software Foundation.                           |
9  |                                                                         |
10  | This program is distributed in the hope that it will be useful,         |
11  | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
12  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
13  | GNU General Public License for more details.                            |
14  |                                                                         |
15  | You should have received a copy of the GNU General Public License along |
16  | with this program; if not, write to the Free Software Foundation, Inc., |
17  | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.             |
18  |                                                                         |
19  +-------------------------------------------------------------------------+
20  | Author: Aleksander Machniak <alec@alec.pl>                              |
21  +-------------------------------------------------------------------------+
22 */
23
24 require_once 'Crypt/GPG.php';
25
26 class enigma_driver_gnupg extends enigma_driver
27 {
28     private $rc;
29     private $gpg;
30     private $homedir;
31     private $user;
32
33     function __construct($user)
34     {
35         $rcmail = rcmail::get_instance();
36         $this->rc = $rcmail;
37         $this->user = $user;
38     }
39
40     /**
41      * Driver initialization and environment checking.
42      * Should only return critical errors.
43      *
44      * @return mixed NULL on success, enigma_error on failure
45      */
46     function init()
47     {
48         $homedir = $this->rc->config->get('enigma_pgp_homedir', INSTALL_PATH . '/plugins/enigma/home');
49
50         if (!$homedir)
51             return new enigma_error(enigma_error::E_INTERNAL,
52                 "Option 'enigma_pgp_homedir' not specified");
53
54         // check if homedir exists (create it if not) and is readable
55         if (!file_exists($homedir))
56             return new enigma_error(enigma_error::E_INTERNAL,
57                 "Keys directory doesn't exists: $homedir");
58         if (!is_writable($homedir))
59             return new enigma_error(enigma_error::E_INTERNAL,
60                 "Keys directory isn't writeable: $homedir");
61
62         $homedir = $homedir . '/' . $this->user;
63
64         // check if user's homedir exists (create it if not) and is readable
65         if (!file_exists($homedir))
66             mkdir($homedir, 0700);
67
68         if (!file_exists($homedir))
69             return new enigma_error(enigma_error::E_INTERNAL,
70                 "Unable to create keys directory: $homedir");
71         if (!is_writable($homedir))
72             return new enigma_error(enigma_error::E_INTERNAL,
73                 "Unable to write to keys directory: $homedir");
74
75         $this->homedir = $homedir;
76
77         // Create Crypt_GPG object
78         try {
79             $this->gpg = new Crypt_GPG(array(
80                 'homedir'   => $this->homedir,
81 //                'debug'     => true,
82           ));
83         }
84         catch (Exception $e) {
85             return $this->get_error_from_exception($e);
86         }
87     }
88
89     function encrypt($text, $keys)
90     {
91 /*
92         foreach ($keys as $key) {
93             $this->gpg->addEncryptKey($key);
94         }
95         $enc = $this->gpg->encrypt($text);
96         return $enc;
97 */
98     }
99
100     function decrypt($text, $key, $passwd)
101     {
102 //        $this->gpg->addDecryptKey($key, $passwd);
103         try {
104             $dec = $this->gpg->decrypt($text);
105             return $dec;
106         }
107         catch (Exception $e) {
108             return $this->get_error_from_exception($e);
109         }
110     }
111
112     function sign($text, $key, $passwd)
113     {
114 /*
115         $this->gpg->addSignKey($key, $passwd);
116         $signed = $this->gpg->sign($text, Crypt_GPG::SIGN_MODE_DETACHED);
117         return $signed;
118 */
119     }
120
121     function verify($text, $signature)
122     {
123         try {
124             $verified = $this->gpg->verify($text, $signature);
125               return $this->parse_signature($verified[0]);
126         }
127         catch (Exception $e) {
128             return $this->get_error_from_exception($e);
129         }
130     }
131
132     public function import($content, $isfile=false)
133     {
134         try {
135             if ($isfile)
136                 return $this->gpg->importKeyFile($content);
137             else
138                 return $this->gpg->importKey($content);
139         }
140         catch (Exception $e) {
141             return $this->get_error_from_exception($e);
142         }
143     }
144     
145     public function list_keys($pattern='')
146     {
147         try {
148             $keys = $this->gpg->getKeys($pattern);
149             $result = array();
150 //print_r($keys);
151             foreach ($keys as $idx => $key) {
152                 $result[] = $this->parse_key($key);
153                 unset($keys[$idx]);
154             }
155 //print_r($result);
156               return $result;
157         }
158         catch (Exception $e) {
159             return $this->get_error_from_exception($e);
160         }
161     }
162     
163     public function get_key($keyid)
164     {
165         $list = $this->list_keys($keyid);
166
167         if (is_array($list))
168             return array_shift($list);
169
170         // error        
171         return $list;
172     }
173
174     public function gen_key($data)
175     {
176     }
177
178     public function del_key($keyid)
179     {
180 //        $this->get_key($keyid);
181         
182         
183     }
184     
185     public function del_privkey($keyid)
186     {
187         try {
188             $this->gpg->deletePrivateKey($keyid);
189             return true;
190         }
191         catch (Exception $e) {
192             return $this->get_error_from_exception($e);
193         }
194     }
195
196     public function del_pubkey($keyid)
197     {
198         try {
199             $this->gpg->deletePublicKey($keyid);
200             return true;
201         }
202         catch (Exception $e) {
203             return $this->get_error_from_exception($e);
204         }
205     }
206     
207     /**
208      * Converts Crypt_GPG exception into Enigma's error object
209      *
210      * @param mixed Exception object
211      *
212      * @return enigma_error Error object
213      */
214     private function get_error_from_exception($e)
215     {
216         $data = array();
217
218         if ($e instanceof Crypt_GPG_KeyNotFoundException) {
219             $error = enigma_error::E_KEYNOTFOUND;
220             $data['id'] = $e->getKeyId();
221         }
222         else if ($e instanceof Crypt_GPG_BadPassphraseException) {
223             $error = enigma_error::E_BADPASS;
224             $data['bad']     = $e->getBadPassphrases();
225             $data['missing'] = $e->getMissingPassphrases();
226         }
227         else if ($e instanceof Crypt_GPG_NoDataException)
228             $error = enigma_error::E_NODATA;
229         else if ($e instanceof Crypt_GPG_DeletePrivateKeyException)
230             $error = enigma_error::E_DELKEY;
231         else
232             $error = enigma_error::E_INTERNAL;
233
234         $msg = $e->getMessage();
235
236         return new enigma_error($error, $msg, $data);
237     }
238
239     /**
240      * Converts Crypt_GPG_Signature object into Enigma's signature object
241      *
242      * @param Crypt_GPG_Signature Signature object
243      *
244      * @return enigma_signature Signature object
245      */
246     private function parse_signature($sig)
247     {
248         $user = $sig->getUserId();
249
250         $data = new enigma_signature();
251         $data->id          = $sig->getId();
252         $data->valid       = $sig->isValid();
253         $data->fingerprint = $sig->getKeyFingerprint();
254         $data->created     = $sig->getCreationDate();
255         $data->expires     = $sig->getExpirationDate();
256         $data->name        = $user->getName();
257         $data->comment     = $user->getComment();
258         $data->email       = $user->getEmail();
259
260         return $data;
261     }
262
263     /**
264      * Converts Crypt_GPG_Key object into Enigma's key object
265      *
266      * @param Crypt_GPG_Key Key object
267      *
268      * @return enigma_key Key object
269      */
270     private function parse_key($key)
271     {
272         $ekey = new enigma_key();
273
274         foreach ($key->getUserIds() as $idx => $user) {
275             $id = new enigma_userid();
276             $id->name    = $user->getName();
277             $id->comment = $user->getComment();
278             $id->email   = $user->getEmail();
279             $id->valid   = $user->isValid();
280             $id->revoked = $user->isRevoked();
281
282             $ekey->users[$idx] = $id;
283         }
284         
285         $ekey->name = trim($ekey->users[0]->name . ' <' . $ekey->users[0]->email . '>');
286
287         foreach ($key->getSubKeys() as $idx => $subkey) {
288                 $skey = new enigma_subkey();
289                 $skey->id          = $subkey->getId();
290                 $skey->revoked     = $subkey->isRevoked();
291                 $skey->created     = $subkey->getCreationDate();
292                 $skey->expires     = $subkey->getExpirationDate();
293                 $skey->fingerprint = $subkey->getFingerprint();
294                 $skey->has_private = $subkey->hasPrivate();
295                 $skey->can_sign    = $subkey->canSign();
296                 $skey->can_encrypt = $subkey->canEncrypt();
297
298                 $ekey->subkeys[$idx] = $skey;
299         };
300         
301         $ekey->id = $ekey->subkeys[0]->id;
302         
303         return $ekey;
304     }
305 }