0
|
1 <?php
|
|
2
|
|
3 /**
|
|
4 +-------------------------------------------------------------------------+
|
|
5 | S/MIME driver for the Enigma Plugin |
|
|
6 | |
|
|
7 | Copyright (C) 2010-2015 The Roundcube Dev Team |
|
|
8 | |
|
|
9 | Licensed under the GNU General Public License version 3 or |
|
|
10 | any later version with exceptions for skins & plugins. |
|
|
11 | See the README file for a full license statement. |
|
|
12 | |
|
|
13 +-------------------------------------------------------------------------+
|
|
14 | Author: Aleksander Machniak <alec@alec.pl> |
|
|
15 +-------------------------------------------------------------------------+
|
|
16 */
|
|
17
|
|
18 class enigma_driver_phpssl extends enigma_driver
|
|
19 {
|
|
20 private $rc;
|
|
21 private $homedir;
|
|
22 private $user;
|
|
23
|
|
24 function __construct($user)
|
|
25 {
|
|
26 $rcmail = rcmail::get_instance();
|
|
27 $this->rc = $rcmail;
|
|
28 $this->user = $user;
|
|
29 }
|
|
30
|
|
31 /**
|
|
32 * Driver initialization and environment checking.
|
|
33 * Should only return critical errors.
|
|
34 *
|
|
35 * @return mixed NULL on success, enigma_error on failure
|
|
36 */
|
|
37 function init()
|
|
38 {
|
|
39 $homedir = $this->rc->config->get('enigma_smime_homedir', INSTALL_PATH . '/plugins/enigma/home');
|
|
40
|
|
41 if (!$homedir)
|
|
42 return new enigma_error(enigma_error::INTERNAL,
|
|
43 "Option 'enigma_smime_homedir' not specified");
|
|
44
|
|
45 // check if homedir exists (create it if not) and is readable
|
|
46 if (!file_exists($homedir))
|
|
47 return new enigma_error(enigma_error::INTERNAL,
|
|
48 "Keys directory doesn't exists: $homedir");
|
|
49 if (!is_writable($homedir))
|
|
50 return new enigma_error(enigma_error::INTERNAL,
|
|
51 "Keys directory isn't writeable: $homedir");
|
|
52
|
|
53 $homedir = $homedir . '/' . $this->user;
|
|
54
|
|
55 // check if user's homedir exists (create it if not) and is readable
|
|
56 if (!file_exists($homedir))
|
|
57 mkdir($homedir, 0700);
|
|
58
|
|
59 if (!file_exists($homedir))
|
|
60 return new enigma_error(enigma_error::INTERNAL,
|
|
61 "Unable to create keys directory: $homedir");
|
|
62 if (!is_writable($homedir))
|
|
63 return new enigma_error(enigma_error::INTERNAL,
|
|
64 "Unable to write to keys directory: $homedir");
|
|
65
|
|
66 $this->homedir = $homedir;
|
|
67
|
|
68 }
|
|
69
|
|
70 function encrypt($text, $keys, $sign_key = null)
|
|
71 {
|
|
72 }
|
|
73
|
|
74 function decrypt($text, $keys = array(), &$signature = null)
|
|
75 {
|
|
76 }
|
|
77
|
|
78 function sign($text, $key, $mode = null)
|
|
79 {
|
|
80 }
|
|
81
|
|
82 function verify($struct, $message)
|
|
83 {
|
|
84 // use common temp dir
|
|
85 $temp_dir = $this->rc->config->get('temp_dir');
|
|
86 $msg_file = tempnam($temp_dir, 'rcmMsg');
|
|
87 $cert_file = tempnam($temp_dir, 'rcmCert');
|
|
88
|
|
89 $fh = fopen($msg_file, "w");
|
|
90 if ($struct->mime_id) {
|
|
91 $message->get_part_body($struct->mime_id, false, 0, $fh);
|
|
92 }
|
|
93 else {
|
|
94 $this->rc->storage->get_raw_body($message->uid, $fh);
|
|
95 }
|
|
96 fclose($fh);
|
|
97
|
|
98 // @TODO: use stored certificates
|
|
99
|
|
100 // try with certificate verification
|
|
101 $sig = openssl_pkcs7_verify($msg_file, 0, $cert_file);
|
|
102 $validity = true;
|
|
103
|
|
104 if ($sig !== true) {
|
|
105 // try without certificate verification
|
|
106 $sig = openssl_pkcs7_verify($msg_file, PKCS7_NOVERIFY, $cert_file);
|
|
107 $validity = enigma_error::UNVERIFIED;
|
|
108 }
|
|
109
|
|
110 if ($sig === true) {
|
|
111 $sig = $this->parse_sig_cert($cert_file, $validity);
|
|
112 }
|
|
113 else {
|
|
114 $errorstr = $this->get_openssl_error();
|
|
115 $sig = new enigma_error(enigma_error::INTERNAL, $errorstr);
|
|
116 }
|
|
117
|
|
118 // remove temp files
|
|
119 @unlink($msg_file);
|
|
120 @unlink($cert_file);
|
|
121
|
|
122 return $sig;
|
|
123 }
|
|
124
|
|
125 public function import($content, $isfile = false, $passwords = array())
|
|
126 {
|
|
127 }
|
|
128
|
|
129 public function export($key, $with_private = false, $passwords = array())
|
|
130 {
|
|
131 }
|
|
132
|
|
133 public function list_keys($pattern='')
|
|
134 {
|
|
135 }
|
|
136
|
|
137 public function get_key($keyid)
|
|
138 {
|
|
139 }
|
|
140
|
|
141 public function gen_key($data)
|
|
142 {
|
|
143 }
|
|
144
|
|
145 public function delete_key($keyid)
|
|
146 {
|
|
147 }
|
|
148
|
|
149 /**
|
|
150 * Returns a name of the hash algorithm used for the last
|
|
151 * signing operation.
|
|
152 *
|
|
153 * @return string Hash algorithm name e.g. sha1
|
|
154 */
|
|
155 public function signature_algorithm()
|
|
156 {
|
|
157 }
|
|
158
|
|
159 /**
|
|
160 * Converts Crypt_GPG_Key object into Enigma's key object
|
|
161 *
|
|
162 * @param Crypt_GPG_Key Key object
|
|
163 *
|
|
164 * @return enigma_key Key object
|
|
165 */
|
|
166 private function parse_key($key)
|
|
167 {
|
|
168 /*
|
|
169 $ekey = new enigma_key();
|
|
170
|
|
171 foreach ($key->getUserIds() as $idx => $user) {
|
|
172 $id = new enigma_userid();
|
|
173 $id->name = $user->getName();
|
|
174 $id->comment = $user->getComment();
|
|
175 $id->email = $user->getEmail();
|
|
176 $id->valid = $user->isValid();
|
|
177 $id->revoked = $user->isRevoked();
|
|
178
|
|
179 $ekey->users[$idx] = $id;
|
|
180 }
|
|
181
|
|
182 $ekey->name = trim($ekey->users[0]->name . ' <' . $ekey->users[0]->email . '>');
|
|
183
|
|
184 foreach ($key->getSubKeys() as $idx => $subkey) {
|
|
185 $skey = new enigma_subkey();
|
|
186 $skey->id = $subkey->getId();
|
|
187 $skey->revoked = $subkey->isRevoked();
|
|
188 $skey->created = $subkey->getCreationDate();
|
|
189 $skey->expires = $subkey->getExpirationDate();
|
|
190 $skey->fingerprint = $subkey->getFingerprint();
|
|
191 $skey->has_private = $subkey->hasPrivate();
|
|
192
|
|
193 $ekey->subkeys[$idx] = $skey;
|
|
194 };
|
|
195
|
|
196 $ekey->id = $ekey->subkeys[0]->id;
|
|
197
|
|
198 return $ekey;
|
|
199 */
|
|
200 }
|
|
201
|
|
202 private function get_openssl_error()
|
|
203 {
|
|
204 $tmp = array();
|
|
205 while ($errorstr = openssl_error_string()) {
|
|
206 $tmp[] = $errorstr;
|
|
207 }
|
|
208
|
|
209 return join("\n", array_values($tmp));
|
|
210 }
|
|
211
|
|
212 private function parse_sig_cert($file, $validity)
|
|
213 {
|
|
214 $cert = openssl_x509_parse(file_get_contents($file));
|
|
215
|
|
216 if (empty($cert) || empty($cert['subject'])) {
|
|
217 $errorstr = $this->get_openssl_error();
|
|
218 return new enigma_error(enigma_error::INTERNAL, $errorstr);
|
|
219 }
|
|
220
|
|
221 $data = new enigma_signature();
|
|
222
|
|
223 $data->id = $cert['hash']; //?
|
|
224 $data->valid = $validity;
|
|
225 $data->fingerprint = $cert['serialNumber'];
|
|
226 $data->created = $cert['validFrom_time_t'];
|
|
227 $data->expires = $cert['validTo_time_t'];
|
|
228 $data->name = $cert['subject']['CN'];
|
|
229 // $data->comment = '';
|
|
230 $data->email = $cert['subject']['emailAddress'];
|
|
231
|
|
232 return $data;
|
|
233 }
|
|
234 }
|