GPGAbstract.php
15.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Crypt_GPG is a package to use GPG from PHP
*
* This package provides an object oriented interface to GNU Privacy
* Guard (GPG). It requires the GPG executable to be on the system.
*
* Though GPG can support symmetric-key cryptography, this package is intended
* only to facilitate public-key cryptography.
*
* This file contains an abstract implementation of a user of the
* {@link Crypt_GPG_Engine} class.
*
* LICENSE:
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/>
*
* @category Encryption
* @package Crypt_GPG
* @author Nathan Fredrickson <nathan@silverorange.com>
* @author Michael Gauthier <mike@silverorange.com>
* @copyright 2005-2013 silverorange
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear.php.net/package/Crypt_GPG
* @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php
* @link http://www.gnupg.org/
*/
/**
* GPG key class
*/
require_once 'Crypt/GPG/Key.php';
/**
* GPG sub-key class
*/
require_once 'Crypt/GPG/SubKey.php';
/**
* GPG user id class
*/
require_once 'Crypt/GPG/UserId.php';
/**
* GPG process and I/O engine class
*/
require_once 'Crypt/GPG/Engine.php';
/**
* Base class for implementing a user of {@link Crypt_GPG_Engine}
*
* @category Encryption
* @package Crypt_GPG
* @author Nathan Fredrickson <nathan@silverorange.com>
* @author Michael Gauthier <mike@silverorange.com>
* @copyright 2005-2013 silverorange
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear.php.net/package/Crypt_GPG
* @link http://www.gnupg.org/
*/
abstract class Crypt_GPGAbstract
{
/**
* Error code returned when there is no error.
*/
const ERROR_NONE = 0;
/**
* Error code returned when an unknown or unhandled error occurs.
*/
const ERROR_UNKNOWN = 1;
/**
* Error code returned when a bad passphrase is used.
*/
const ERROR_BAD_PASSPHRASE = 2;
/**
* Error code returned when a required passphrase is missing.
*/
const ERROR_MISSING_PASSPHRASE = 3;
/**
* Error code returned when a key that is already in the keyring is
* imported.
*/
const ERROR_DUPLICATE_KEY = 4;
/**
* Error code returned the required data is missing for an operation.
*
* This could be missing key data, missing encrypted data or missing
* signature data.
*/
const ERROR_NO_DATA = 5;
/**
* Error code returned when an unsigned key is used.
*/
const ERROR_UNSIGNED_KEY = 6;
/**
* Error code returned when a key that is not self-signed is used.
*/
const ERROR_NOT_SELF_SIGNED = 7;
/**
* Error code returned when a public or private key that is not in the
* keyring is used.
*/
const ERROR_KEY_NOT_FOUND = 8;
/**
* Error code returned when an attempt to delete public key having a
* private key is made.
*/
const ERROR_DELETE_PRIVATE_KEY = 9;
/**
* Error code returned when one or more bad signatures are detected.
*/
const ERROR_BAD_SIGNATURE = 10;
/**
* Error code returned when there is a problem reading GnuPG data files.
*/
const ERROR_FILE_PERMISSIONS = 11;
/**
* Error code returned when a key could not be created.
*/
const ERROR_KEY_NOT_CREATED = 12;
/**
* Error code returned when bad key parameters are used during key
* generation.
*/
const ERROR_BAD_KEY_PARAMS = 13;
/**
* URI at which package bugs may be reported.
*/
const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG';
/**
* Engine used to control the GPG subprocess
*
* @var Crypt_GPG_Engine
*
* @see Crypt_GPGAbstract::setEngine()
*/
protected $engine = null;
/**
* Creates a new GPG object
*
* Available options are:
*
* - <kbd>string homedir</kbd> - the directory where the GPG keyring files are
* stored. If not specified, Crypt_GPG uses the default
* of <kbd>~/.gnupg</kbd>.
* - <kbd>string publicKeyring</kbd> - the file path of the public keyring.
* Use this if the public keyring is not in the homedir,
* or if the keyring is in a directory not writable
* by the process invoking GPG (like Apache). Then you
* can specify the path to the keyring with this option
* (/foo/bar/pubring.gpg), and specify a writable directory
* (like /tmp) using the <i>homedir</i> option.
* - <kbd>string privateKeyring</kbd> - the file path of the private keyring.
* Use this if the private keyring is not in the homedir,
* or if the keyring is in a directory not writable
* by the process invoking GPG (like Apache). Then
* you can specify the path to the keyring with this option
* (/foo/bar/secring.gpg), and specify a writable directory
* (like /tmp) using the <i>homedir</i> option.
* - <kbd>string trustDb</kbd> - the file path of the web-of-trust database.
* Use this if the trust database is not in the homedir, or
* if the database is in a directory not writable
* by the process invoking GPG (like Apache). Then you can
* specify the path to the trust database with this option
* (/foo/bar/trustdb.gpg), and specify a writable directory
* (like /tmp) using the <i>homedir</i> option.
* - <kbd>string binary</kbd> - the location of the GPG binary.
* If not specified, the driver attempts to auto-detect
* the GPG binary location using a list of known default
* locations for the current operating system. The option
* <kbd>gpgBinary</kbd> is a deprecated alias.
* - <kbd>string agent</kbd> - the location of the GnuPG agent binary.
* The gpg-agent is only used for GnuPG 2.x. If not
* specified, the engine attempts to auto-detect
* the gpg-agent binary location using a list of
* know default locations for the current operating system.
* - <kbd>string|false gpgconf</kbd> - the location of the GnuPG conf binary.
* The gpgconf is only used for GnuPG >= 2.1. If not
* specified, the engine attempts to auto-detect
* the location using a list of know default locations.
* When set to FALSE `gpgconf --kill` will not be executed
* via destructor.
* - <kbd>string digest-algo</kbd> - Sets the message digest algorithm.
* - <kbd>string cipher-algo</kbd> - Sets the symmetric cipher.
* - <kbd>string compress-algo</kbd> - Sets the compression algorithm.
* - <kbd>boolean strict</kbd> - In strict mode clock problems on subkeys
* and signatures are not ignored (--ignore-time-conflict
* and --ignore-valid-from options).
* - <kbd>mixed debug</kbd> - whether or not to use debug mode.
* When debug mode is on, all communication to and from
* the GPG subprocess is logged. This can be useful to
* diagnose errors when using Crypt_GPG.
* - <kbd>array options</kbd> - additional per-command options to the GPG
* command. Key of the array is a command (e.g.
* gen-key, import, sign, encrypt, list-keys).
* Value is a string containing command line arguments to be
* added to the related command. For example:
* array('sign' => '--emit-version').
*
* @param array $options optional. An array of options used to create the
* GPG object. All options are optional and are
* represented as key-value pairs.
*
* @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist
* and cannot be created. This can happen if <kbd>homedir</kbd> is
* not specified, Crypt_GPG is run as the web user, and the web
* user has no home directory. This exception is also thrown if any
* of the options <kbd>publicKeyring</kbd>,
* <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are
* specified but the files do not exist or are are not readable.
* This can happen if the user running the Crypt_GPG process (for
* example, the Apache user) does not have permission to read the
* files.
*
* @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or
* if no <kbd>binary</kbd> is provided and no suitable binary could
* be found.
*
* @throws PEAR_Exception if the provided <kbd>agent</kbd> is invalid, or
* if no <kbd>agent</kbd> is provided and no suitable gpg-agent
* could be found.
*/
public function __construct(array $options = array())
{
$this->setEngine(new Crypt_GPG_Engine($options));
}
/**
* Sets the I/O engine to use for GnuPG operations
*
* Normally this method does not need to be used. It provides a means for
* dependency injection.
*
* @param Crypt_GPG_Engine $engine the engine to use.
*
* @return Crypt_GPGAbstract the current object, for fluent interface.
*/
public function setEngine(Crypt_GPG_Engine $engine)
{
$this->engine = $engine;
return $this;
}
/**
* Sets per-command additional arguments
*
* @param array $options Additional per-command options for GPG command.
* Note: This will unset options set previously.
* Key of the array is a command (e.g.
* gen-key, import, sign, encrypt, list-keys).
* Value is a string containing command line arguments to be
* added to the related command. For example:
* array('sign' => '--emit-version').
*
* @return Crypt_GPGAbstract the current object, for fluent interface.
*/
public function setEngineOptions(array $options)
{
$this->engine->setOptions($options);
return $this;
}
/**
* Returns version of the engine (GnuPG) used for operation.
*
* @return string GnuPG version.
*
* @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
* Use the <kbd>debug</kbd> option and file a bug report if these
* exceptions occur.
*/
public function getVersion()
{
return $this->engine->getVersion();
}
/**
* Gets the available keys in the keyring
*
* Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See
* the first section of <b>doc/DETAILS</b> in the
* {@link http://www.gnupg.org/download/ GPG package} for a detailed
* description of how the GPG command output is parsed.
*
* @param string $keyId optional. Only keys with that match the specified
* pattern are returned. The pattern may be part of
* a user id, a key id or a key fingerprint. If not
* specified, all keys are returned.
*
* @return array an array of {@link Crypt_GPG_Key} objects. If no keys
* match the specified <kbd>$keyId</kbd> an empty array is
* returned.
*
* @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
* Use the <kbd>debug</kbd> option and file a bug report if these
* exceptions occur.
*
* @see Crypt_GPG_Key
*/
protected function _getKeys($keyId = '')
{
// get private key fingerprints
if ($keyId == '') {
$operation = '--list-secret-keys';
} else {
$operation = '--utf8-strings --list-secret-keys -- ' . escapeshellarg($keyId);
}
// According to The file 'doc/DETAILS' in the GnuPG distribution, using
// double '--with-fingerprint' also prints the fingerprint for subkeys.
$arguments = array(
'--with-colons',
'--with-fingerprint',
'--with-fingerprint',
'--fixed-list-mode'
);
$output = '';
$this->engine->reset();
$this->engine->setOutput($output);
$this->engine->setOperation($operation, $arguments);
$this->engine->run();
$privateKeyFingerprints = array();
foreach (explode(PHP_EOL, $output) as $line) {
$lineExp = explode(':', $line);
if ($lineExp[0] == 'fpr') {
$privateKeyFingerprints[] = $lineExp[9];
}
}
// get public keys
if ($keyId == '') {
$operation = '--list-public-keys';
} else {
$operation = '--utf8-strings --list-public-keys -- ' . escapeshellarg($keyId);
}
$output = '';
$this->engine->reset();
$this->engine->setOutput($output);
$this->engine->setOperation($operation, $arguments);
$this->engine->run();
$keys = array();
$key = null; // current key
$subKey = null; // current sub-key
foreach (explode(PHP_EOL, $output) as $line) {
$lineExp = explode(':', $line);
if ($lineExp[0] == 'pub') {
// new primary key means last key should be added to the array
if ($key !== null) {
$keys[] = $key;
}
$key = new Crypt_GPG_Key();
$subKey = Crypt_GPG_SubKey::parse($line);
$key->addSubKey($subKey);
} elseif ($lineExp[0] == 'sub') {
$subKey = Crypt_GPG_SubKey::parse($line);
$key->addSubKey($subKey);
} elseif ($lineExp[0] == 'fpr') {
$fingerprint = $lineExp[9];
// set current sub-key fingerprint
$subKey->setFingerprint($fingerprint);
// if private key exists, set has private to true
if (in_array($fingerprint, $privateKeyFingerprints)) {
$subKey->setHasPrivate(true);
}
} elseif ($lineExp[0] == 'uid') {
$string = stripcslashes($lineExp[9]); // as per documentation
$userId = new Crypt_GPG_UserId($string);
if ($lineExp[1] == 'r') {
$userId->setRevoked(true);
}
$key->addUserId($userId);
}
}
// add last key
if ($key !== null) {
$keys[] = $key;
}
return $keys;
}
}